extend demon2 with explicit separation between blocking ctrl mechanisms & passive access/introspection/writing mechanisms; extend demon2 api with access mechanism

This commit is contained in:
Ryan Fleury
2024-03-22 15:53:04 -07:00
parent 07bbf1b43c
commit c636e1ad2e
6 changed files with 293 additions and 195 deletions
+35 -34
View File
@@ -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;
+10 -10
View File
@@ -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
+25 -5
View File
@@ -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);
+209 -138
View File
@@ -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;
}
+5
View File
@@ -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
+9 -8
View File
@@ -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)