diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 936d4d03..1987676d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1717,6 +1717,7 @@ ctrl_thread__entry_point(void *p) { ThreadNameF("[ctrl] thread"); ProfBeginFunction(); + DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin(); //- rjf: loop Temp scratch = scratch_begin(0, 0); @@ -1746,13 +1747,13 @@ ctrl_thread__entry_point(void *p) case CTRL_MsgKind_COUNT:{}break; //- rjf: target operations - case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(msg);}break; - case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (msg);}break; - case CTRL_MsgKind_Attach: {ctrl_thread__attach (msg);}break; - case CTRL_MsgKind_Kill: {ctrl_thread__kill (msg);}break; - case CTRL_MsgKind_Detach: {ctrl_thread__detach (msg);}break; - case CTRL_MsgKind_Run: {ctrl_thread__run (msg); done = 1;}break; - case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (msg); done = 1;}break; + case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(ctrl_ctx, msg);}break; + case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break; + case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break; //- rjf: configuration case CTRL_MsgKind_SetUserEntryPoints: @@ -1899,7 +1900,7 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID //- rjf: attached process running/event gathering internal DMN_Event * -ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) +ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) { ProfBeginFunction(); DMN_Event *event = push_array(arena, DMN_Event, 1); @@ -2042,8 +2043,8 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls } } - //- rjf: no event -> dmn_run for a new one - if(got_event == 0) ProfScope("no event -> dmn_run for a new one") + //- rjf: no event -> dmn_ctrl_run for a new one + if(got_event == 0) ProfScope("no event -> dmn_ctrl_run for a new one") { // rjf: prep spoof B32 do_spoof = (spoof != 0 && dmn_handle_match(run_ctrls->single_step_thread, dmn_handle_zero())); @@ -2065,7 +2066,7 @@ ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls // rjf: run for new events ProfScope("run for new events") { - DMN_EventList events = dmn_run(scratch.arena, run_ctrls); + DMN_EventList events = dmn_ctrl_run(scratch.arena, ctrl_ctx, run_ctrls); for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) { DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node; @@ -2255,7 +2256,7 @@ ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) //- rjf: msg kind implementations internal void -ctrl_thread__launch_and_handshake(CTRL_Msg *msg) +ctrl_thread__launch_and_handshake(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2269,7 +2270,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = dmn_launch_process(&opts); + U32 id = dmn_ctrl_launch(ctrl_ctx, &opts); //- rjf: record start { @@ -2296,7 +2297,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) // rjf: run until handshake-signifying events for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2363,7 +2364,7 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) } internal void -ctrl_thread__launch_and_init(CTRL_Msg *msg) +ctrl_thread__launch_and_init(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2378,7 +2379,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = dmn_launch_process(&opts); + U32 id = dmn_ctrl_launch(ctrl_ctx, &opts); ////////////////////////////// //- rjf: record start @@ -2402,7 +2403,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2686,14 +2687,14 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) } internal void -ctrl_thread__attach(CTRL_Msg *msg) +ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach - B32 attach_successful = dmn_attach_process(msg->entity_id); + B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, msg->entity_id); //- rjf: run to handshake if(attach_successful) @@ -2704,7 +2705,7 @@ ctrl_thread__attach(CTRL_Msg *msg) run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -2739,7 +2740,7 @@ ctrl_thread__attach(CTRL_Msg *msg) } internal void -ctrl_thread__kill(CTRL_Msg *msg) +ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2748,7 +2749,7 @@ ctrl_thread__kill(CTRL_Msg *msg) U32 exit_code = msg->exit_code; //- rjf: send kill - B32 kill_worked = dmn_kill_process(process, exit_code); + B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code); //- rjf: wait for process to be dead if(kill_worked) @@ -2760,7 +2761,7 @@ ctrl_thread__kill(CTRL_Msg *msg) run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; @@ -2788,7 +2789,7 @@ ctrl_thread__kill(CTRL_Msg *msg) } internal void -ctrl_thread__detach(CTRL_Msg *msg) +ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2796,7 +2797,7 @@ ctrl_thread__detach(CTRL_Msg *msg) DMN_Handle process = msg->entity; //- rjf: detach - B32 detach_worked = dmn_detach_process(process); + B32 detach_worked = dmn_ctrl_detach(ctrl_ctx, process); //- rjf: wait for process to be dead if(detach_worked) @@ -2808,7 +2809,7 @@ ctrl_thread__detach(CTRL_Msg *msg) run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) { done = 1; @@ -2836,7 +2837,7 @@ ctrl_thread__detach(CTRL_Msg *msg) } internal void -ctrl_thread__run(CTRL_Msg *msg) +ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -2959,7 +2960,7 @@ ctrl_thread__run(CTRL_Msg *msg) run_ctrls.single_step_thread = node->v; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; @@ -3062,7 +3063,7 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: get next event // - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, run_spoof); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, run_spoof); ////////////////////////// //- rjf: determine event handling @@ -3298,7 +3299,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3369,7 +3370,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = target_thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3454,7 +3455,7 @@ ctrl_thread__run(CTRL_Msg *msg) single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; @@ -3539,7 +3540,7 @@ ctrl_thread__run(CTRL_Msg *msg) } internal void -ctrl_thread__single_step(CTRL_Msg *msg) +ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -3561,7 +3562,7 @@ ctrl_thread__single_step(CTRL_Msg *msg) run_ctrls.single_step_thread = msg->entity; for(B32 done = 0; done == 0;) { - DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index f74f2a83..2ac62d9b 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -699,23 +699,23 @@ internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); internal void ctrl_thread__entry_point(void *p); //- rjf: breakpoint resolution -internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); -internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //- rjf: attached process running/event gathering -internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); +internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); //- rjf: eval helpers internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size); //- rjf: msg kind implementations -internal void ctrl_thread__launch_and_handshake(CTRL_Msg *msg); -internal void ctrl_thread__launch_and_init(CTRL_Msg *msg); -internal void ctrl_thread__attach(CTRL_Msg *msg); -internal void ctrl_thread__kill(CTRL_Msg *msg); -internal void ctrl_thread__detach(CTRL_Msg *msg); -internal void ctrl_thread__run(CTRL_Msg *msg); -internal void ctrl_thread__single_step(CTRL_Msg *msg); +internal void ctrl_thread__launch_and_handshake(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__launch_and_init(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// //~ rjf: Memory-Stream Thread Functions diff --git a/src/demon2/demon2_core.h b/src/demon2/demon2_core.h index adb84bd4..6ff8e2d3 100644 --- a/src/demon2/demon2_core.h +++ b/src/demon2/demon2_core.h @@ -4,6 +4,20 @@ #ifndef DEMON2_CORE_H #define DEMON2_CORE_H +//////////////////////////////// +//~ rjf: Control-Thread-Only Context +// +// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only +// used by the thread which called it. All APIs which can ONLY run on the +// control thread, which blocks to control & receive events, will take this +// parameter. All other APIs can be called from any thread. + +typedef struct DMN_CtrlCtx DMN_CtrlCtx; +struct DMN_CtrlCtx +{ + U64 u64 [1]; +}; + //////////////////////////////// //~ rjf: Handle Types @@ -174,11 +188,12 @@ internal void dmn_init(void); //////////////////////////////// //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) -internal U32 dmn_launch_process(OS_LaunchOptions *options); -internal B32 dmn_attach_process(U32 pid); -internal B32 dmn_kill_process(DMN_Handle process, U32 exit_code); -internal B32 dmn_detach_process(DMN_Handle process); -internal DMN_EventList dmn_run(Arena *arena, DMN_RunCtrls *ctrls); +internal DMN_CtrlCtx *dmn_ctrl_begin(void); +internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options); +internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid); +internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code); +internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process); +internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls); //////////////////////////////// //~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) @@ -193,6 +208,11 @@ internal U64 dmn_run_gen(void); internal U64 dmn_mem_gen(void); internal U64 dmn_reg_gen(void); +//- rjf: non-blocking-control-thread access barriers +internal B32 dmn_access_open(void); +internal void dmn_access_close(void); +#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close()) + //- rjf: processes internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index ddf921c9..6a86c4e5 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -1073,6 +1073,7 @@ dmn_init(void) Arena *arena = arena_alloc(); dmn_w32_shared = push_array(arena, DMN_W32_Shared, 1); dmn_w32_shared->arena = arena; + dmn_w32_shared->access_mutex = os_mutex_alloc(); dmn_w32_shared->detach_arena = arena_alloc(); dmn_w32_shared->entities_arena = arena_alloc__sized(GB(8), KB(64)); dmn_w32_shared->entities_base = dmn_w32_entity_alloc(&dmn_w32_entity_nil, DMN_W32_EntityKind_Root, 0); @@ -1110,102 +1111,111 @@ dmn_init(void) //////////////////////////////// //~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) +internal DMN_CtrlCtx * +dmn_ctrl_begin(void) +{ + DMN_CtrlCtx *ctx = (DMN_CtrlCtx *)1; + dmn_w32_ctrl_thread = 1; + return ctx; +} + internal U32 -dmn_launch_process(OS_LaunchOptions *options) +dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options) { Temp scratch = scratch_begin(0, 0); U32 result = 0; - - //- rjf: produce exe / arguments string - String8 cmd = {0}; - if(options->cmd_line.first != 0) + DMN_AccessScope { - String8List args = {0}; - String8 exe_path = options->cmd_line.first->string; - str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); - for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) + //- rjf: produce exe / arguments string + String8 cmd = {0}; + if(options->cmd_line.first != 0) { - str8_list_push(scratch.arena, &args, n->string); - } - StringJoin join_params = {0}; - join_params.sep = str8_lit(" "); - cmd = str8_list_join(scratch.arena, &args, &join_params); - } - - //- rjf: produce environment strings - String8 env = {0}; - { - String8List all_opts = options->env; - if(options->inherit_env != 0) - { - MemoryZeroStruct(&all_opts); - str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); - for(String8Node *n = options->env.first; n != 0; n = n->next) + String8List args = {0}; + String8 exe_path = options->cmd_line.first->string; + str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); + for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) { - str8_list_push(scratch.arena, &all_opts, n->string); - } - for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); + str8_list_push(scratch.arena, &args, n->string); } + StringJoin join_params = {0}; + join_params.sep = str8_lit(" "); + cmd = str8_list_join(scratch.arena, &args, &join_params); } - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - env = str8_list_join(scratch.arena, &all_opts, &join_params2); - } - - //- rjf: produce utf-16 strings - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - //- rjf: launch - DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - AllocConsole(); - if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) - { - // check if we are 32-bit app, and just close it immediately - BOOL is_wow = 0; - IsWow64Process(process_info.hProcess, &is_wow); - if(is_wow) + + //- rjf: produce environment strings + String8 env = {0}; { - MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); - DebugActiveProcessStop(process_info.dwProcessId); - TerminateProcess(process_info.hProcess,0xffffffff); + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + MemoryZeroStruct(&all_opts); + str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + //- rjf: produce utf-16 strings + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + //- rjf: launch + DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + AllocConsole(); + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + { + // check if we are 32-bit app, and just close it immediately + BOOL is_wow = 0; + IsWow64Process(process_info.hProcess, &is_wow); + if(is_wow) + { + MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); + DebugActiveProcessStop(process_info.dwProcessId); + TerminateProcess(process_info.hProcess,0xffffffff); + } + else + { + result = process_info.dwProcessId; + dmn_w32_shared->new_process_pending = 1; + } + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); } else { - result = process_info.dwProcessId; - dmn_w32_shared->new_process_pending = 1; + MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); + } + FreeConsole(); + + //- rjf: eliminate all handles which have stuck around from the AllocConsole + { + SetStdHandle(STD_INPUT_HANDLE, 0); + SetStdHandle(STD_OUTPUT_HANDLE, 0); + SetStdHandle(STD_ERROR_HANDLE, 0); } - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); } - else - { - MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); - } - FreeConsole(); - - //- rjf: eliminate all handles which have stuck around from the AllocConsole - { - SetStdHandle(STD_INPUT_HANDLE, 0); - SetStdHandle(STD_OUTPUT_HANDLE, 0); - SetStdHandle(STD_ERROR_HANDLE, 0); - } - scratch_end(scratch); return result; } internal B32 -dmn_attach_process(U32 pid) +dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) { B32 result = 0; - if(DebugActiveProcess((DWORD)pid)) + DMN_AccessScope if(DebugActiveProcess((DWORD)pid)) { result = 1; dmn_w32_shared->new_process_pending = 1; @@ -1214,57 +1224,63 @@ dmn_attach_process(U32 pid) } internal B32 -dmn_kill_process(DMN_Handle process, U32 exit_code) +dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) { B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - if(TerminateProcess(process_entity->handle, exit_code)) + DMN_AccessScope { - result = 1; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + if(TerminateProcess(process_entity->handle, exit_code)) + { + result = 1; + } } return result; } internal B32 -dmn_detach_process(DMN_Handle process) +dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) { B32 result = 0; - DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); - - // rjf: resume threads - for(DMN_W32_Entity *child = process_entity->first; - child != &dmn_w32_entity_nil; - child = child->next) + DMN_AccessScope { - if(child->kind == DMN_W32_EntityKind_Thread) + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + + // rjf: resume threads + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) { - DWORD resume_result = ResumeThread(child->handle); - (void)resume_result; + if(child->kind == DMN_W32_EntityKind_Thread) + { + DWORD resume_result = ResumeThread(child->handle); + (void)resume_result; + } + } + + // rjf: detach + { + DWORD pid = (DWORD)process_entity->id; + if(DebugActiveProcessStop(pid)) + { + result = 1; + } + } + + // rjf: push into list of processes to generate events for later + if(result != 0) + { + dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); } } - - // rjf: detach - { - DWORD pid = (DWORD)process_entity->id; - if(DebugActiveProcessStop(pid)) - { - result = 1; - } - } - - // rjf: push into list of processes to generate events for later - if(result != 0) - { - dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); - } - return result; } internal DMN_EventList -dmn_run(Arena *arena, DMN_RunCtrls *ctrls) +dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { DMN_EventList events = {0}; + dmn_access_open(); ////////////////////////////// //- rjf: determine event generation path @@ -2319,6 +2335,7 @@ dmn_run(Arena *arena, DMN_RunCtrls *ctrls) }break; } + dmn_access_close(); return events; } @@ -2378,21 +2395,56 @@ dmn_reg_gen(void) return result; } +//- rjf: non-blocking-control-thread access barriers + +internal B32 +dmn_access_open(void) +{ + B32 result = 0; + if(dmn_w32_ctrl_thread) + { + result = 1; + } + else + { + os_mutex_take(dmn_w32_shared->access_mutex); + result = !dmn_w32_shared->access_run_state; + } + return result; +} + +internal void +dmn_access_close(void) +{ + if(!dmn_w32_ctrl_thread) + { + os_mutex_drop(dmn_w32_shared->access_mutex); + } +} + //- rjf: processes internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); - U64 result = dmn_w32_process_read(entity->handle, range, dst); + U64 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_read(entity->handle, range, dst); + } return result; } internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); - B32 result = dmn_w32_process_write(entity->handle, range, src); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_write(entity->handle, range, src); + } return result; } @@ -2401,37 +2453,45 @@ dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) internal Architecture dmn_arch_from_thread(DMN_Handle handle) { - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); - return entity->arch; + Architecture arch = Architecture_Null; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + arch = entity->arch; + } + return arch; } internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle) { U64 result = 0; - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - if(thread->kind == DMN_W32_EntityKind_Thread) + DMN_AccessScope { - DMN_W32_Entity *process = thread->parent; - U64 tlb = thread->thread.thread_local_base; - switch(thread->arch) + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + if(thread->kind == DMN_W32_EntityKind_Thread) { - case Architecture_Null: - case Architecture_COUNT: - {}break; - case Architecture_arm64: - case Architecture_arm32: - {NotImplemented;}break; - case Architecture_x64: + DMN_W32_Entity *process = thread->parent; + U64 tlb = thread->thread.thread_local_base; + switch(thread->arch) { - U64 stack_base_addr = tlb + 0x8; - dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result); - }break; - case Architecture_x86: - { - U64 stack_base_addr = tlb + 0x4; - dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result); - }break; + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + case Architecture_x64: + { + U64 stack_base_addr = tlb + 0x8; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result); + }break; + case Architecture_x86: + { + U64 stack_base_addr = tlb + 0x4; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result); + }break; + } } } return result; @@ -2441,10 +2501,13 @@ internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle) { U64 result = 0; - DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); - if(entity->kind == DMN_W32_EntityKind_Thread) + DMN_AccessScope { - result = entity->thread.thread_local_base; + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + if(entity->kind == DMN_W32_EntityKind_Thread) + { + result = entity->thread.thread_local_base; + } } return result; } @@ -2452,16 +2515,24 @@ dmn_tls_root_vaddr_from_thread(DMN_Handle handle) internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block) { - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - B32 result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block); + } return result; } internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) { - DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); - B32 result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block); + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block); + } return result; } diff --git a/src/demon2/win32/demon2_core_win32.h b/src/demon2/win32/demon2_core_win32.h index d75ee249..15e2e3ac 100644 --- a/src/demon2/win32/demon2_core_win32.h +++ b/src/demon2/win32/demon2_core_win32.h @@ -194,6 +194,10 @@ struct DMN_W32_Shared Arena *arena; String8List env_strings; + // rjf: access locking mechanism + OS_Handle access_mutex; + B32 access_run_state; + // rjf: run/mem/reg gens U64 run_gen; U64 mem_gen; @@ -232,6 +236,7 @@ struct DMN_W32_Shared global DMN_W32_Shared *dmn_w32_shared = 0; global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil}; global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0; +thread_static B32 dmn_w32_ctrl_thread = 0; //////////////////////////////// //~ rjf: Basic Helpers diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 11efef73..c28a1950 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -1,18 +1,21 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Demon2 Pass Tasks +// +// [ ] solidify synchronization mechanisms for usage of demon2 layer +// [ ] TLS eval correctness +// [ ] TLS eval -> in-process-memory EXE info +// [ ] unwinding -> in-process-memory EXE info +// [ ] freezing thread while running -> soft-halt + //////////////////////////////// //~ rjf: Frontend/UI Pass Tasks // -// [x] hover-eval when window is not focused - maybe just start directly -// using mouse-move events here -// [x] CRT asserts - stepping over int 29 should work just like stepping over -// an int3 -// [ ] check new callstack caching rules very strongly // [ ] committing needs to happen when navigating focus away for any reason // [ ] better discoverability for view rules - have better help hover tooltip, // info on arguments, and better autocomplete lister -// [ ] freezing thread while running -> soft-halt // // [ ] source view -> floating margin/line-nums // [ ] theme colors -> more explicit about e.g. opaque backgrounds vs. floating @@ -81,8 +84,6 @@ // [ ] disasm animation & go-to-address // // [ ] visualize remapped files (via path map) -// -// [x] DBGI layer is case-sensitive even on case-insensitive systems //////////////////////////////// //~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)