mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-25 21:14:59 -07:00
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:
+35
-34
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user