begin floating thread/frame selection mechanisms into frontend and out of engine

This commit is contained in:
Ryan Fleury
2024-09-12 14:58:48 -07:00
parent 638140ab87
commit 3641c212b2
9 changed files with 282 additions and 196 deletions
-6
View File
@@ -252,14 +252,8 @@ D_CmdTable: // | | | |
{Restart 1 1 Null null Nil 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all running processes, then restarts the targets which were used to launch all current processes (if any)." "restart,retry" }
{StepInto 1 1 Null null Nil 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either line or instructions." "" }
{StepOver 1 1 Null null Nil 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either line or instructions." "" }
{RunToCursor 1 1 Null null Nil 0 0 0 0 0 0 Play "run_to_cursor" "Run To Cursor" "Runs the selected thread to the current cursor." "line" }
{SetNextStatement 1 1 Null null Nil 0 0 0 0 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" }
//- rjf: debug control context management operations
{SelectThread 1 1 Entity null Thread 0 0 0 0 0 1 Null "select_thread" "Select Thread" "Selects a thread." "" }
{SelectUnwind 0 1 Null null Nil 0 0 0 0 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" }
{UpOneFrame 1 1 Null null Nil 0 0 0 0 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the call stack frame above the currently selected." "" }
{DownOneFrame 1 1 Null null Nil 0 0 0 0 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the call stack frame below the currently selected." "callstack,unwind" }
{FreezeThread 1 1 Entity null Thread 0 0 0 0 0 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" }
{ThawThread 1 1 Entity null Thread 0 0 0 0 0 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" }
{FreezeProcess 1 1 Entity null Process 0 0 0 0 0 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" }
+64 -160
View File
@@ -3859,12 +3859,12 @@ d_init(void)
d_state->ctrl_last_run_arena = arena_alloc();
}
internal CTRL_EventList
internal D_EventList
d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
CTRL_EventList result = {0};
D_EventList result = {0};
d_state->frame_index += 1;
arena_clear(d_frame_arena());
d_state->frame_eval_memread_endt_us = os_now_microseconds() + 5000;
@@ -3881,9 +3881,9 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
U64 new_reg_gen = ctrl_reg_gen();
//- rjf: consume & process events
result = ctrl_c2u_pop_events(arena);
ctrl_entity_store_apply_events(d_state->ctrl_entity_store, &result);
for(CTRL_EventNode *event_n = result.first;
CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena);
ctrl_entity_store_apply_events(d_state->ctrl_entity_store, &events);
for(CTRL_EventNode *event_n = events.first;
event_n != 0;
event_n = event_n->next)
{
@@ -3914,7 +3914,30 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
B32 should_snap = !(d_state->ctrl_soft_halt_issued);
d_state->ctrl_is_running = 0;
d_state->ctrl_soft_halt_issued = 0;
D_Entity *stop_thread = d_entity_from_ctrl_handle(event->entity);
// rjf: exception or unexpected trap -> push error
if(event->cause == CTRL_EventCause_InterruptedByException ||
event->cause == CTRL_EventCause_InterruptedByTrap)
{
log_user_error(str8_zero());
}
// rjf: kill all entities which are marked to die on stop
{
D_Entity *request = d_entity_from_id(event->msg_id);
if(d_entity_is_nil(request))
{
for(D_Entity *entity = d_entity_root();
!d_entity_is_nil(entity);
entity = d_entity_rec_depth_first_pre(entity, d_entity_root()).next)
{
if(entity->flags & D_EntityFlag_DiesOnRunStop)
{
d_entity_mark_for_deletion(entity);
}
}
}
}
// rjf: gather stop info
{
@@ -3923,6 +3946,26 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
d_state->ctrl_last_stop_event.string = push_str8_copy(d_state->ctrl_stop_arena, d_state->ctrl_last_stop_event.string);
}
// rjf: push stop event to caller, if this is not a soft-halt
if(should_snap)
{
D_EventCause cause = D_EventCause_Null;
switch(event->cause)
{
default:{}break;
case CTRL_EventCause_UserBreakpoint:{cause = D_EventCause_UserBreakpoint;}break;
}
D_EventNode *n = push_array(arena, D_EventNode, 1);
SLLQueuePush(result.first, result.last, n);
result.count += 1;
D_Event *evt = &n->v;
evt->kind = D_EventKind_Stop;
evt->cause = cause;
evt->vaddr = event->rip_vaddr;
}
#if 0 // TODO(rjf): @msgs
D_Entity *stop_thread = d_entity_from_ctrl_handle(event->entity);
// rjf: select & snap to thread causing stop
if(should_snap && stop_thread->kind == D_EntityKind_Thread)
{
@@ -3931,7 +3974,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
}
// rjf: if no stop-causing thread, and if selected thread, snap to selected
#if 0 // TODO(rjf): @msgs
if(should_snap && d_entity_is_nil(stop_thread))
{
D_Entity *selected_thread = d_entity_from_handle(d_regs()->thread);
@@ -3940,7 +3982,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
df_cmd(DF_CmdKind_FindThread, .thread = d_handle_from_entity(selected_thread));
}
}
#endif
// rjf: thread hit user breakpoint -> increment breakpoint hit count
if(should_snap && event->cause == CTRL_EventCause_UserBreakpoint)
@@ -3981,30 +4022,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
}
}
}
// rjf: exception or unexpected trap -> push error
if(event->cause == CTRL_EventCause_InterruptedByException ||
event->cause == CTRL_EventCause_InterruptedByTrap)
{
log_user_error(str8_zero());
}
// rjf: kill all entities which are marked to die on stop
{
D_Entity *request = d_entity_from_id(event->msg_id);
if(d_entity_is_nil(request))
{
for(D_Entity *entity = d_entity_root();
!d_entity_is_nil(entity);
entity = d_entity_rec_depth_first_pre(entity, d_entity_root()).next)
{
if(entity->flags & D_EntityFlag_DiesOnRunStop)
{
d_entity_mark_for_deletion(entity);
}
}
}
}
#endif
}break;
//- rjf: entity creation/deletion
@@ -4096,6 +4114,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
// rjf: equip color
d_entity_equip_color_rgba(entity, thread_color);
#if 0 // TODO(rjf): @msgs
// rjf: automatically select if we don't have a selected thread
D_Entity *selected_thread = d_entity_from_handle(d_state->base_regs.v.thread);
if(d_entity_is_nil(selected_thread))
@@ -4110,6 +4129,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
{
d_cmd(D_CmdKind_SelectThread, .entity = d_handle_from_entity(entity));
}
#endif
}break;
case CTRL_EventKind_NewModule:
@@ -4673,15 +4693,13 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
ctrl_halt();
}break;
case D_CmdKind_SoftHaltRefresh:
if(d_ctrl_targets_running())
{
if(d_ctrl_targets_running())
{
need_run = 1;
run_kind = d_state->ctrl_last_run_kind;
run_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, d_state->ctrl_last_run_thread_handle);
run_flags = d_state->ctrl_last_run_flags;
run_traps = d_state->ctrl_last_run_traps;
}
need_run = 1;
run_kind = d_state->ctrl_last_run_kind;
run_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, d_state->ctrl_last_run_thread_handle);
run_flags = d_state->ctrl_last_run_flags;
run_traps = d_state->ctrl_last_run_traps;
}break;
case D_CmdKind_SetThreadIP:
{
@@ -4776,7 +4794,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
case D_CmdKind_StepInto:
case D_CmdKind_StepOver:
{
D_EntityList processes = d_query_cached_entity_list_with_kind(D_EntityKind_Process);
CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process);
if(processes.count != 0)
{
D_CmdKind step_cmd_kind = (cmd->kind == D_CmdKind_StepInto
@@ -4797,127 +4815,8 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
d_cmd(D_CmdKind_LaunchAndInit, .entity_list = d_handle_list_from_entity_list(scratch.arena, targets));
}
}break;
case D_CmdKind_RunToCursor:
{
String8 file_path = d_regs()->file_path;
if(file_path.size != 0)
{
d_cmd(D_CmdKind_RunToLine, .file_path = file_path, .text_point = d_regs()->cursor);
}
else
{
d_cmd(D_CmdKind_RunToAddress, .vaddr = d_regs()->vaddr_range.min);
}
}break;
case D_CmdKind_SetNextStatement:
{
D_Entity *thread = d_entity_from_handle(d_regs()->thread);
String8 file_path = d_regs()->file_path;
U64 new_rip_vaddr = d_regs()->vaddr_range.min;
if(file_path.size != 0)
{
D_LineList *lines = &d_regs()->lines;
for(D_LineNode *n = lines->first; n != 0; n = n->next)
{
D_EntityList modules = d_modules_from_dbgi_key(scratch.arena, &n->v.dbgi_key);
D_Entity *module = d_module_from_thread_candidates(thread, &modules);
if(!d_entity_is_nil(module))
{
new_rip_vaddr = d_vaddr_from_voff(module, n->v.voff_range.min);
break;
}
}
}
d_cmd(D_CmdKind_SetThreadIP, .entity = d_handle_from_entity(thread), .vaddr = new_rip_vaddr);
}break;
//- rjf: debug control context management operations
case D_CmdKind_SelectThread:
{
D_Entity *thread = d_entity_from_handle(params.entity);
D_Entity *module = d_module_from_thread(thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
d_state->base_regs.v.unwind_count = 0;
d_state->base_regs.v.inline_depth = 0;
d_state->base_regs.v.thread = d_handle_from_entity(thread);
d_state->base_regs.v.module = d_handle_from_entity(module);
d_state->base_regs.v.process = d_handle_from_entity(process);
#if 0 // TODO(rjf): @msgs
df_cmd(DF_CmdKind_FindThread, .thread = d_handle_from_entity(thread));
#endif
}break;
case D_CmdKind_SelectUnwind:
{
DI_Scope *di_scope = di_scope_open();
D_Entity *thread = d_entity_from_handle(d_state->base_regs.v.thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread);
D_Unwind rich_unwind = d_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
if(params.unwind_index < rich_unwind.frames.concrete_frame_count)
{
D_UnwindFrame *frame = &rich_unwind.frames.v[params.unwind_index];
d_state->base_regs.v.unwind_count = params.unwind_index;
d_state->base_regs.v.inline_depth = 0;
if(params.inline_depth <= frame->inline_frame_count)
{
d_state->base_regs.v.inline_depth = params.inline_depth;
}
}
#if 0 // TODO(rjf): @msgs
df_cmd(DF_CmdKind_FindThread, .thread = d_handle_from_entity(thread));
#endif
di_scope_close(di_scope);
}break;
case D_CmdKind_UpOneFrame:
case D_CmdKind_DownOneFrame:
{
DI_Scope *di_scope = di_scope_open();
D_Entity *thread = d_entity_from_handle(d_state->base_regs.v.thread);
D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process);
CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread);
D_Unwind rich_unwind = d_unwind_from_ctrl_unwind(scratch.arena, di_scope, process, &base_unwind);
U64 crnt_unwind_idx = d_state->base_regs.v.unwind_count;
U64 crnt_inline_dpt = d_state->base_regs.v.inline_depth;
U64 next_unwind_idx = crnt_unwind_idx;
U64 next_inline_dpt = crnt_inline_dpt;
if(crnt_unwind_idx < rich_unwind.frames.concrete_frame_count)
{
D_UnwindFrame *f = &rich_unwind.frames.v[crnt_unwind_idx];
switch(cmd->kind)
{
default:{}break;
case D_CmdKind_UpOneFrame:
{
if(crnt_inline_dpt < f->inline_frame_count)
{
next_inline_dpt += 1;
}
else if(crnt_unwind_idx > 0)
{
next_unwind_idx -= 1;
next_inline_dpt = 0;
}
}break;
case D_CmdKind_DownOneFrame:
{
if(crnt_inline_dpt > 0)
{
next_inline_dpt -= 1;
}
else if(crnt_unwind_idx < rich_unwind.frames.concrete_frame_count)
{
next_unwind_idx += 1;
next_inline_dpt = (f+1)->inline_frame_count;
}
}break;
}
}
d_cmd(D_CmdKind_SelectUnwind,
.unwind_index = next_unwind_idx,
.inline_depth = next_inline_dpt);
di_scope_close(di_scope);
}break;
case D_CmdKind_FreezeThread:
case D_CmdKind_ThawThread:
case D_CmdKind_FreezeProcess:
@@ -5068,6 +4967,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints)
ctrl_msg_list_concat_in_place(&d_state->ctrl_msgs, &msgs_copy);
if(d_state->ctrl_msgs.count != 0)
{
if(!d_state->ctrl_soft_halt_issued && d_state->ctrl_is_running)
{
d_state->ctrl_soft_halt_issued = 1;
ctrl_halt();
}
if(ctrl_u2c_push_msgs(&d_state->ctrl_msgs, os_now_microseconds()+100))
{
MemoryZeroStruct(&d_state->ctrl_msgs);
+44 -1
View File
@@ -41,6 +41,49 @@ struct D_BreakpointArray
U64 count;
};
////////////////////////////////
//~ rjf: Tick Output Types
typedef enum D_EventKind
{
D_EventKind_Null,
D_EventKind_Stop,
D_EventKind_COUNT
}
D_EventKind;
typedef enum D_EventCause
{
D_EventCause_Null,
D_EventCause_UserBreakpoint,
D_EventCause_COUNT
}
D_EventCause;
typedef struct D_Event D_Event;
struct D_Event
{
D_EventKind kind;
D_EventCause cause;
CTRL_Handle thread;
U64 vaddr;
};
typedef struct D_EventNode D_EventNode;
struct D_EventNode
{
D_EventNode *next;
D_Event v;
};
typedef struct D_EventList D_EventList;
struct D_EventList
{
D_EventNode *first;
D_EventNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Handles
@@ -1046,6 +1089,6 @@ internal B32 d_next_cmd(D_Cmd **cmd);
//~ rjf: Main Layer Top-Level Calls
internal void d_init(void);
internal CTRL_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints);
internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints);
#endif // DBG_ENGINE_CORE_H
@@ -107,12 +107,6 @@ D_CmdKind_Run,
D_CmdKind_Restart,
D_CmdKind_StepInto,
D_CmdKind_StepOver,
D_CmdKind_RunToCursor,
D_CmdKind_SetNextStatement,
D_CmdKind_SelectThread,
D_CmdKind_SelectUnwind,
D_CmdKind_UpOneFrame,
D_CmdKind_DownOneFrame,
D_CmdKind_FreezeThread,
D_CmdKind_ThawThread,
D_CmdKind_FreezeProcess,