diff --git a/src/dbg_engine/dbg_engine.mdesk b/src/dbg_engine/dbg_engine.mdesk index e785b4b2..44f7fb42 100644 --- a/src/dbg_engine/dbg_engine.mdesk +++ b/src/dbg_engine/dbg_engine.mdesk @@ -95,6 +95,7 @@ D_EntityKindTable: D_RegTable: { // rjf: entity slots + {D_Handle machine Machine } {D_Handle module Module } {D_Handle process Process } {D_Handle thread Thread } @@ -122,6 +123,7 @@ D_RegTable: {Rng1U64 voff_range VoffRange } // rjf: general parameters + {U32 pid PID } {B32 force_confirm ForceConfirm } {B32 prefer_disasm PreferDisasm } {Dir2 dir2 Dir2 } @@ -258,7 +260,8 @@ D_MsgKindTable: @enum D_MsgKind: { - @expand(D_MsgKindTable a) `$(a.name)` + @expand(D_MsgKindTable a) `$(a.name)`, + COUNT } @data(String8) d_msg_kind_name_lower_table: diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index c97ff225..b9f26447 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -123,6 +123,10 @@ d_regs_copy_contents(Arena *arena, D_Regs *dst, D_Regs *src) dst->dbgi_key = di_key_copy(arena, &src->dbgi_key); dst->string = push_str8_copy(arena, src->string); dst->params_tree = md_tree_copy(arena, src->params_tree); + if(dst->entity_list.count == 0 && !d_handle_match(d_handle_zero(), dst->entity)) + { + d_handle_list_push(arena, &dst->entity_list, dst->entity); + } } internal D_Regs * @@ -6258,6 +6262,7 @@ d_init(CmdLine *cmdln, D_StateDeltaHistory *hist) d_state->seconds_til_autosave = 0.5f; d_state->hist = hist; d_state->top_regs = &d_state->base_regs; + d_state->msgs_arena = arena_alloc(); // rjf: set up initial exception filtering rules for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) @@ -6388,7 +6393,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) d_state->top_regs = &d_state->base_regs; d_regs_copy_contents(d_frame_arena(), &d_state->top_regs->v, &d_state->top_regs->v); + ////////////////////////////// //- rjf: sync with ctrl thread + // ProfScope("sync with ctrl thread") { Temp scratch = scratch_begin(&arena, 1); @@ -6799,7 +6806,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) scratch_end(scratch); } + ////////////////////////////// //- rjf: eliminate entities that are marked for deletion + // ProfScope("eliminate deleted entities") { for(D_Entity *entity = d_entity_root(), *next = 0; !d_entity_is_nil(entity); entity = next) @@ -6825,7 +6834,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } + ////////////////////////////// //- rjf: garbage collect eliminated thread unwinds + // for(U64 slot_idx = 0; slot_idx < d_state->unwind_cache.slots_count; slot_idx += 1) { D_UnwindCacheSlot *slot = &d_state->unwind_cache.slots[slot_idx]; @@ -6841,7 +6852,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } + ////////////////////////////// //- rjf: sync with di parsers + // ProfScope("sync with di parsers") { Temp scratch = scratch_begin(&arena, 1); @@ -6870,7 +6883,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) scratch_end(scratch); } + ////////////////////////////// //- rjf: start/stop telemetry captures + // ProfScope("start/stop telemetry captures") { if(!ProfIsCapturing() && DEV_telemetry_capture) @@ -6883,13 +6898,909 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } + ////////////////////////////// + //- rjf: process messages + // + ProfScope("process messages") + { + Temp scratch = scratch_begin(&arena, 1); + for(D_MsgNode *n = d_state->msgs.first; n != 0; n = n->next) + { + temp_end(scratch); + D_Msg *msg = &n->v; + D_Regs *regs = msg->regs; + D_RegsScope + { + d_regs_copy_contents(scratch.arena, d_regs(), regs); + switch(msg->kind) + { + default:{}break; + + //- rjf: [low level target operations] target launching + case D_MsgKind_LaunchAndRun: + case D_MsgKind_LaunchAndInit: + { + // rjf: get list of targets to launch + D_EntityList targets = d_entity_list_from_handle_list(scratch.arena, regs->entity_list); + + // rjf: no targets => assume all active targets + if(targets.count == 0) + { + targets = d_push_active_target_list(scratch.arena); + } + + // rjf: launch + if(targets.count != 0) + { + for(D_EntityNode *n = targets.first; n != 0; n = n->next) + { + // rjf: extract data from target + D_Entity *target = n->entity; + String8 name = d_entity_child_from_kind(target, D_EntityKind_Executable)->string; + String8 args = d_entity_child_from_kind(target, D_EntityKind_Arguments)->string; + String8 path = d_entity_child_from_kind(target, D_EntityKind_WorkingDirectory)->string; + String8 entry= d_entity_child_from_kind(target, D_EntityKind_EntryPoint)->string; + name = str8_skip_chop_whitespace(name); + args = str8_skip_chop_whitespace(args); + path = str8_skip_chop_whitespace(path); + entry = str8_skip_chop_whitespace(entry); + if(path.size == 0) + { + path = os_get_current_path(scratch.arena); + } + + // rjf: build launch options + String8List cmdln_strings = {0}; + { + str8_list_push(scratch.arena, &cmdln_strings, name); + { + U64 start_split_idx = 0; + B32 quoted = 0; + for(U64 idx = 0; idx <= args.size; idx += 1) + { + U8 byte = idx < args.size ? args.str[idx] : 0; + if(byte == '"') + { + quoted ^= 1; + } + B32 splitter_found = (!quoted && (byte == 0 || char_is_space(byte))); + if(splitter_found) + { + String8 string = str8_substr(args, r1u64(start_split_idx, idx)); + if(string.size > 0) + { + str8_list_push(scratch.arena, &cmdln_strings, string); + } + start_split_idx = idx+1; + } + } + } + } + + // rjf: push message to launch + { + CTRL_Msg msg = {CTRL_MsgKind_Launch}; + msg.path = path; + msg.cmd_line_string_list = cmdln_strings; + msg.env_inherit = 1; + MemoryCopyArray(msg.exception_code_filters, d_state->ctrl_exception_code_filters); + str8_list_push(scratch.arena, &msg.entry_points, entry); + d_push_ctrl_msg(&msg); + } + } + + // rjf: run + d_ctrl_run(D_RunKind_Run, &d_nil_entity, CTRL_RunFlag_StopOnEntryPoint * (msg->kind == D_MsgKind_LaunchAndInit), 0); + } + + // rjf: no targets -> error + if(targets.count == 0) + { + log_user_errorf("No active targets exist; cannot launch."); + } + }break; + + //- rjf: [low level target operations] killing + case D_MsgKind_Kill: + { + D_EntityList processes = d_entity_list_from_handle_list(scratch.arena, regs->entity_list); + + // rjf: no processes => kill everything + if(processes.count == 0) + { + processes = d_query_cached_entity_list_with_kind(D_EntityKind_Process); + } + + // rjf: kill processes + if(processes.count != 0) + { + for(D_EntityNode *n = processes.first; n != 0; n = n->next) + { + D_Entity *process = n->entity; + CTRL_Msg msg = {CTRL_MsgKind_Kill}; + { + msg.exit_code = 1; + msg.machine_id = process->ctrl_machine_id; + msg.entity = process->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, d_state->ctrl_exception_code_filters); + } + d_push_ctrl_msg(&msg); + } + } + + // rjf: no processes -> error + if(processes.count == 0) + { + log_user_errorf("No attached running processes exist; cannot kill."); + } + }break; + case D_MsgKind_KillAll: + { + d_msg(D_MsgKind_Kill); + }break; + + //- rjf: [low level target operations] attaching / detaching + case D_MsgKind_Attach: + { + U32 pid = regs->pid; + if(pid != 0) + { + CTRL_Msg msg = {CTRL_MsgKind_Attach}; + msg.entity_id = pid; + MemoryCopyArray(msg.exception_code_filters, d_state->ctrl_exception_code_filters); + d_push_ctrl_msg(&msg); + } + }break; + case D_MsgKind_Detach: + { + for(D_HandleNode *n = regs->entity_list.first; n != 0; n = n->next) + { + D_Entity *entity = d_entity_from_handle(n->handle); + if(entity->kind == D_EntityKind_Process) + { + CTRL_Msg msg = {CTRL_MsgKind_Detach}; + msg.machine_id = entity->ctrl_machine_id; + msg.entity = entity->ctrl_handle; + MemoryCopyArray(msg.exception_code_filters, d_state->ctrl_exception_code_filters); + d_push_ctrl_msg(&msg); + } + } + }break; + + //- rjf: [low level target operations] continuing from halted state + case D_MsgKind_Continue: + { + B32 good_to_run = 0; + D_EntityList machines = d_query_cached_entity_list_with_kind(D_EntityKind_Machine); + for(D_EntityNode *n = machines.first; n != 0; n = n->next) + { + D_Entity *machine = n->entity; + if(!d_entity_is_frozen(machine)) + { + good_to_run = 1; + break; + } + } + if(good_to_run) + { + d_ctrl_run(D_RunKind_Run, &d_nil_entity, 0, 0); + } + else + { + log_user_errorf("Cannot run with all threads frozen."); + } + }break; + + //- rjf: [low level target operations] stepping + case D_MsgKind_StepIntoInst: + case D_MsgKind_StepOverInst: + case D_MsgKind_StepIntoLine: + case D_MsgKind_StepOverLine: + case D_MsgKind_StepOut: + { + D_Entity *thread = d_entity_from_handle(regs->thread); + if(d_ctrl_targets_running()) + { + if(d_ctrl_last_run_kind() == D_RunKind_Run) + { + log_user_errorf("Must halt before stepping."); + } + } + else if(d_entity_is_frozen(thread)) + { + log_user_errorf("Must thaw selected thread before stepping."); + } + else + { + B32 good = 1; + CTRL_TrapList traps = {0}; + switch(msg->kind) + { + default:{}break; + case D_MsgKind_StepIntoInst: {}break; + case D_MsgKind_StepOverInst: {traps = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; + case D_MsgKind_StepIntoLine: {traps = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; + case D_MsgKind_StepOverLine: {traps = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; + case D_MsgKind_StepOut: + { + // rjf: thread => full unwind + CTRL_Unwind unwind = ctrl_unwind_from_thread(scratch.arena, d_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+10000); + + // rjf: use first unwind frame to generate trap + if(unwind.flags == 0 && unwind.frames.count > 1) + { + U64 vaddr = regs_rip_from_arch_block(thread->arch, unwind.frames.v[1].regs); + CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; + ctrl_trap_list_push(scratch.arena, &traps, &trap); + } + else + { + log_user_errorf("Could not find the return address of the current callstack frame successfully."); + good = 0; + } + }break; + } + if(good && traps.count != 0) + { + d_ctrl_run(D_RunKind_Step, thread, 0, &traps); + } + if(good && traps.count == 0) + { + d_ctrl_run(D_RunKind_SingleStep, thread, 0, &traps); + } + } + }break; + + //- rjf: [low level target operations] halting + case D_MsgKind_Halt: + { + if(d_ctrl_targets_running()) + { + ctrl_halt(); + } + }break; + case D_MsgKind_SoftHaltRefresh: + { + if(d_ctrl_targets_running()) + { + d_ctrl_run(d_state->ctrl_last_run_kind, d_entity_from_handle(d_state->ctrl_last_run_thread), d_state->ctrl_last_run_flags, &d_state->ctrl_last_run_traps); + } + }break; + + //- rjf: [low level target operations] setting thread rip + case D_MsgKind_SetThreadIP: + { + D_Entity *thread = d_entity_from_handle(regs->thread); + U64 vaddr = regs->vaddr_range.min; + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, d_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); + regs_arch_block_write_rip(thread->arch, block, vaddr); + B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block); + + // rjf: early mutation of unwind cache for immediate frontend effect + if(result) + { + D_UnwindCache *cache = &d_state->unwind_cache; + if(cache->slots_count != 0) + { + D_Handle thread_handle = d_handle_from_entity(thread); + U64 hash = d_hash_from_string(str8_struct(&thread_handle)); + U64 slot_idx = hash%cache->slots_count; + D_UnwindCacheSlot *slot = &cache->slots[slot_idx]; + for(D_UnwindCacheNode *n = slot->first; n != 0; n = n->next) + { + if(d_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0) + { + regs_arch_block_write_rip(thread->arch, n->unwind.frames.v[0].regs, vaddr); + break; + } + } + } + } + }break; + + //- rjf: high level target operations [running] + case D_MsgKind_RunToLine: + { + String8 file_path = regs->file_path; + TxtPt pt = regs->cursor; + D_Entity *bp = d_entity_alloc(d_entity_root(), D_EntityKind_Breakpoint); + d_entity_equip_cfg_src(bp, D_CfgSrc_Transient); + bp->flags |= D_EntityFlag_DiesOnRunStop; + D_Entity *loc = d_entity_alloc(bp, D_EntityKind_Location); + d_entity_equip_name(loc, file_path); + d_entity_equip_txt_pt(loc, pt); + d_msg(D_MsgKind_Run); + }break; + case D_MsgKind_RunToAddress: + { + D_Entity *bp = d_entity_alloc(d_entity_root(), D_EntityKind_Breakpoint); + d_entity_equip_cfg_src(bp, D_CfgSrc_Transient); + bp->flags |= D_EntityFlag_DiesOnRunStop; + D_Entity *loc = d_entity_alloc(bp, D_EntityKind_Location); + d_entity_equip_vaddr(loc, regs->vaddr_range.min); + d_msg(D_MsgKind_Run); + }break; + case D_MsgKind_Run: + { + D_EntityList processes = d_query_cached_entity_list_with_kind(D_EntityKind_Process); + if(processes.count != 0) + { + d_msg(D_MsgKind_Continue); + } + else if(!d_ctrl_targets_running()) + { + d_msg(D_MsgKind_LaunchAndRun); + } + }break; + case D_MsgKind_Restart: + { + // rjf: kill all + { + d_msg(D_MsgKind_KillAll); + } + + // rjf: gather targets corresponding to all launched processes + D_EntityList targets = {0}; + { + D_EntityList processes = d_query_cached_entity_list_with_kind(D_EntityKind_Process); + for(D_EntityNode *n = processes.first; n != 0; n = n->next) + { + D_Entity *process = n->entity; + D_Entity *target = d_entity_from_handle(process->entity_handle); + if(!d_entity_is_nil(target)) + { + d_entity_list_push(scratch.arena, &targets, target); + } + } + } + + // rjf: re-launch targets + { + d_msg(D_MsgKind_LaunchAndRun, .entity_list = d_handle_list_from_entity_list(scratch.arena, targets)); + } + }break; + + //- rjf: high level target operations [stepping] + case D_MsgKind_StepInto: + case D_MsgKind_StepOver: + { + D_EntityList processes = d_query_cached_entity_list_with_kind(D_EntityKind_Process); + if(processes.count != 0) + { + D_MsgKind step_msg_kind = (msg->kind == D_MsgKind_StepInto + ? D_MsgKind_StepIntoLine + : D_MsgKind_StepOverLine); + if(regs->prefer_disasm) + { + step_msg_kind = (msg->kind == D_MsgKind_StepInto + ? D_MsgKind_StepIntoInst + : D_MsgKind_StepOverInst); + } + d_msg(step_msg_kind); + } + else if(!d_ctrl_targets_running()) + { + D_EntityList targets = d_push_active_target_list(scratch.arena); + d_msg(D_MsgKind_LaunchAndInit, .entity_list = d_handle_list_from_entity_list(scratch.arena, targets)); + } + }break; + + //- rjf: thread / frame selection + case D_MsgKind_SelectThread: + { + D_Entity *thread = d_entity_from_handle(regs->thread); + 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); + }break; + case D_MsgKind_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(regs->unwind_count < rich_unwind.frames.concrete_frame_count) + { + D_UnwindFrame *frame = &rich_unwind.frames.v[regs->unwind_count]; + d_state->base_regs.v.unwind_count = regs->unwind_count; + d_state->base_regs.v.inline_depth = 0; + if(regs->inline_depth <= frame->inline_frame_count) + { + d_state->base_regs.v.inline_depth = regs->inline_depth; + } + } + di_scope_close(di_scope); + }break; + case D_MsgKind_UpOneFrame: + case D_MsgKind_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(msg->kind) + { + default:{}break; + case D_MsgKind_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_MsgKind_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_msg(D_MsgKind_SelectUnwind, + .unwind_count = next_unwind_idx, + .inline_depth = next_inline_dpt); + di_scope_close(di_scope); + }break; + + //- rjf: thread freezing/thawing + case D_MsgKind_FreezeThread: {d_msg(D_MsgKind_FreezeEntity, .entity = regs->thread);}break; + case D_MsgKind_ThawThread: {d_msg(D_MsgKind_ThawEntity, .entity = regs->thread);}break; + case D_MsgKind_FreezeProcess: {d_msg(D_MsgKind_FreezeEntity, .entity = regs->process);}break; + case D_MsgKind_ThawProcess: {d_msg(D_MsgKind_ThawEntity, .entity = regs->process);}break; + case D_MsgKind_FreezeMachine: {d_msg(D_MsgKind_FreezeEntity, .entity = regs->machine);}break; + case D_MsgKind_ThawMachine: {d_msg(D_MsgKind_ThawEntity, .entity = regs->machine);}break; + case D_MsgKind_FreezeLocalMachine: + { + D_Entity *machine = d_machine_entity_from_machine_id(CTRL_MachineID_Local); + d_msg(D_MsgKind_FreezeEntity, .entity = d_handle_from_entity(machine)); + }break; + case D_MsgKind_ThawLocalMachine: + { + D_Entity *machine = d_machine_entity_from_machine_id(CTRL_MachineID_Local); + d_msg(D_MsgKind_ThawEntity, .entity = d_handle_from_entity(machine)); + }break; + + //- rjf: path overrides (TODO(rjf)) + case D_MsgKind_SetFileOverrideLinkSrc:{}break; + case D_MsgKind_SetFileOverrideLinkDst:{}break; + case D_MsgKind_SetFileReplacementPath:{}break; + + //- rjf: auto view rules (TODO(rjf)) + case D_MsgKind_SetAutoViewRuleType:{}break; + case D_MsgKind_SetAutoViewRuleViewRule:{}break; + + //- rjf: general entity operations + case D_MsgKind_EnableEntity: + case D_MsgKind_EnableBreakpoint: + case D_MsgKind_EnableTarget: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + d_entity_equip_disabled(entity, 0); + }break; + case D_MsgKind_DisableEntity: + case D_MsgKind_DisableBreakpoint: + case D_MsgKind_DisableTarget: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + d_entity_equip_disabled(entity, 1); + }break; + case D_MsgKind_FreezeEntity: + case D_MsgKind_ThawEntity: + { + B32 should_freeze = (msg->kind == D_MsgKind_FreezeEntity); + D_Entity *root = d_entity_from_handle(regs->entity); + for(D_Entity *e = root; + !d_entity_is_nil(e); + e = d_entity_rec_depth_first_pre(e, root).next) + { + if(e->kind == D_EntityKind_Thread) + { + d_set_thread_freeze_state(e, should_freeze); + } + } + }break; + case D_MsgKind_RemoveEntity: + case D_MsgKind_RemoveBreakpoint: + case D_MsgKind_RemoveTarget: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + D_EntityKindFlags kind_flags = d_entity_kind_flags_table[entity->kind]; + if(kind_flags & D_EntityKindFlag_CanDelete) + { + d_entity_mark_for_deletion(entity); + } + }break; + case D_MsgKind_NameEntity: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + String8 string = regs->string; + d_entity_equip_name(entity, string); + }break; + case D_MsgKind_DuplicateEntity: + { + D_Entity *src = d_entity_from_handle(regs->entity); + if(!d_entity_is_nil(src)) + { + typedef struct Task Task; + struct Task + { + Task *next; + D_Entity *src_n; + D_Entity *dst_parent; + }; + Task starter_task = {0, src, src->parent}; + Task *first_task = &starter_task; + Task *last_task = &starter_task; + for(Task *task = first_task; task != 0; task = task->next) + { + D_Entity *src_n = task->src_n; + D_Entity *dst_n = d_entity_alloc(task->dst_parent, task->src_n->kind); + if(src_n->flags & D_EntityFlag_HasTextPoint) {d_entity_equip_txt_pt(dst_n, src_n->text_point);} + if(src_n->flags & D_EntityFlag_HasU64) {d_entity_equip_u64(dst_n, src_n->u64);} + if(src_n->flags & D_EntityFlag_HasColor) {d_entity_equip_color_hsva(dst_n, d_hsva_from_entity(src_n));} + if(src_n->flags & D_EntityFlag_HasVAddrRng) {d_entity_equip_vaddr_rng(dst_n, src_n->vaddr_rng);} + if(src_n->flags & D_EntityFlag_HasVAddr) {d_entity_equip_vaddr(dst_n, src_n->vaddr);} + if(src_n->disabled) {d_entity_equip_disabled(dst_n, 1);} + if(src_n->string.size != 0) {d_entity_equip_name(dst_n, src_n->string);} + dst_n->cfg_src = src_n->cfg_src; + for(D_Entity *src_child = task->src_n->first; !d_entity_is_nil(src_child); src_child = src_child->next) + { + Task *child_task = push_array(scratch.arena, Task, 1); + child_task->src_n = src_child; + child_task->dst_parent = dst_n; + SLLQueuePush(first_task, last_task, child_task); + } + } + } + }break; + case D_MsgKind_RelocateEntity: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + D_Entity *location = d_entity_child_from_kind(entity, D_EntityKind_Location); + if(d_entity_is_nil(location)) + { + location = d_entity_alloc(entity, D_EntityKind_Location); + } + location->flags &= ~D_EntityFlag_HasTextPoint; + location->flags &= ~D_EntityFlag_HasVAddr; + if(regs->cursor.line != 0) + { + d_entity_equip_txt_pt(location, regs->cursor); + } + if(regs->vaddr_range.min != 0) + { + d_entity_equip_vaddr(location, regs->vaddr_range.min); + } + if(regs->file_path.size != 0) + { + d_entity_equip_name(location, regs->file_path); + } + }break; + + //- rjf: breakpoints + case D_MsgKind_AddBreakpoint: + case D_MsgKind_ToggleBreakpoint: + { + String8 file_path = regs->file_path; + TxtPt pt = regs->cursor; + String8 string = regs->string; + U64 vaddr = regs->vaddr_range.min; + B32 removed_already_existing = 0; + if(msg->kind == D_MsgKind_ToggleBreakpoint) + { + D_EntityList bps = d_query_cached_entity_list_with_kind(D_EntityKind_Breakpoint); + for(D_EntityNode *n = bps.first; n != 0; n = n->next) + { + D_Entity *bp = n->entity; + D_Entity *loc = d_entity_child_from_kind(bp, D_EntityKind_Location); + if((loc->flags & D_EntityFlag_HasTextPoint && path_match_normalized(loc->string, file_path) && loc->text_point.line == pt.line) || + (loc->flags & D_EntityFlag_HasVAddr && loc->vaddr == vaddr) || + (!(loc->flags & D_EntityFlag_HasTextPoint) && str8_match(loc->string, string, 0))) + { + d_entity_mark_for_deletion(bp); + removed_already_existing = 1; + break; + } + } + } + if(!removed_already_existing) + { + D_Entity *bp = d_entity_alloc(d_entity_root(), D_EntityKind_Breakpoint); + d_entity_equip_cfg_src(bp, D_CfgSrc_Project); + D_Entity *loc = d_entity_alloc(bp, D_EntityKind_Location); + if(file_path.size != 0 && pt.line != 0) + { + d_entity_equip_name(loc, file_path); + d_entity_equip_txt_pt(loc, pt); + } + else if(string.size != 0) + { + d_entity_equip_name(loc, string); + } + else if(vaddr != 0) + { + d_entity_equip_vaddr(loc, vaddr); + } + } + }break; + case D_MsgKind_AddAddressBreakpoint: + case D_MsgKind_AddFunctionBreakpoint: + { + d_msg(D_MsgKind_AddBreakpoint); + }break; + + //- rjf: watch pins + case D_MsgKind_AddWatchPin: + case D_MsgKind_ToggleWatchPin: + { + String8 file_path = regs->file_path; + TxtPt pt = regs->cursor; + String8 string = regs->string; + U64 vaddr = regs->vaddr_range.min; + B32 removed_already_existing = 0; + if(msg->kind == D_MsgKind_ToggleWatchPin) + { + D_EntityList wps = d_query_cached_entity_list_with_kind(D_EntityKind_WatchPin); + for(D_EntityNode *n = wps.first; n != 0; n = n->next) + { + D_Entity *wp = n->entity; + D_Entity *loc = d_entity_child_from_kind(wp, D_EntityKind_Location); + if((loc->flags & D_EntityFlag_HasTextPoint && path_match_normalized(loc->string, file_path) && loc->text_point.line == pt.line) || + (loc->flags & D_EntityFlag_HasVAddr && loc->vaddr == vaddr) || + (!(loc->flags & D_EntityFlag_HasTextPoint) && str8_match(loc->string, string, 0))) + { + d_entity_mark_for_deletion(wp); + removed_already_existing = 1; + break; + } + } + } + if(!removed_already_existing) + { + D_Entity *wp = d_entity_alloc(d_entity_root(), D_EntityKind_WatchPin); + d_entity_equip_name(wp, string); + d_entity_equip_cfg_src(wp, D_CfgSrc_Project); + D_Entity *loc = d_entity_alloc(wp, D_EntityKind_Location); + if(file_path.size != 0 && pt.line != 0) + { + d_entity_equip_name(loc, file_path); + d_entity_equip_txt_pt(loc, pt); + } + else if(vaddr != 0) + { + d_entity_equip_vaddr(loc, vaddr); + } + } + }break; + + //- rjf: watch expressions + case D_MsgKind_ToggleWatchExpression: + if(regs->string.size != 0) + { + D_Entity *existing_watch = d_entity_from_name_and_kind(regs->string, D_EntityKind_Watch); + if(d_entity_is_nil(existing_watch)) + { + D_Entity *watch = &d_nil_entity; + D_StateDeltaHistoryBatch(d_state_delta_history()) + { + watch = d_entity_alloc(d_entity_root(), D_EntityKind_Watch); + } + d_entity_equip_cfg_src(watch, D_CfgSrc_Project); + d_entity_equip_name(watch, regs->string); + } + else + { + d_entity_mark_for_deletion(existing_watch); + } + }break; + + //- rjf: at-cursor operations + case D_MsgKind_ToggleBreakpointAtCursor:{d_msg(D_MsgKind_ToggleBreakpoint);}break; + case D_MsgKind_ToggleWatchPinAtCursor:{d_msg(D_MsgKind_ToggleWatchPin);}break; + case D_MsgKind_GoToNameAtCursor: + case D_MsgKind_ToggleWatchExpressionAtCursor: + { + // rjf: get expr + String8 expr = {0}; + { + HS_Scope *hs_scope = hs_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + U128 text_key = regs->text_key; + TXT_LangKind lang_kind = regs->lang_kind; + TxtRng range = txt_rng(regs->cursor, regs->mark); + U128 hash = {0}; + TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, text_key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + Rng1U64 expr_off_range = {0}; + if(range.min.column != range.max.column) + { + expr_off_range = r1u64(txt_off_from_info_pt(&info, range.min), txt_off_from_info_pt(&info, range.max)); + } + else + { + expr_off_range = txt_expr_off_range_from_info_data_pt(&info, data, range.min); + } + expr = push_str8_copy(scratch.arena, str8_substr(data, expr_off_range)); + txt_scope_close(txt_scope); + hs_scope_close(hs_scope); + } + + // rjf: push command for this expr + // TODO(rjf): @msgs + // d_msg(msg->kind == D_MsgKind_GoToNameAtCursor ? D_MsgKind_GoToName : + // msg->kind == D_MsgKind_ToggleWatchExpressionAtCursor ? D_MsgKind_ToggleWatchExpression : + // D_MsgKind_GoToName, .string = expr); + }break; + {}break; + case D_MsgKind_RunToCursor: + { + String8 file_path = regs->file_path; + if(file_path.size != 0) + { + d_msg(D_MsgKind_RunToLine); + } + else + { + d_msg(D_MsgKind_RunToAddress); + } + }break; + case D_MsgKind_SetNextStatement: + { + D_Entity *thread = d_entity_from_handle(regs->thread); + String8 file_path = regs->file_path; + U64 new_rip_vaddr = regs->vaddr_range.min; + if(file_path.size != 0) + { + D_LineList *lines = ®s->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_msg(D_MsgKind_SetThreadIP, .thread = regs->thread, .vaddr_range = r1u64(new_rip_vaddr, 0)); + }break; + + //- rjf: targets + case D_MsgKind_AddTarget: + { + D_Entity *entity = d_entity_alloc(d_entity_root(), D_EntityKind_Target); + d_entity_equip_disabled(entity, 1); + d_entity_equip_cfg_src(entity, D_CfgSrc_Project); + D_Entity *exe = d_entity_alloc(entity, D_EntityKind_Executable); + d_entity_equip_name(exe, regs->file_path); + String8 working_dir = str8_chop_last_slash(regs->file_path); + if(working_dir.size != 0) + { + String8 working_dir_path = push_str8f(scratch.arena, "%S/", working_dir); + D_Entity *execution_path = d_entity_alloc(entity, D_EntityKind_WorkingDirectory); + d_entity_equip_name(execution_path, working_dir_path); + } + d_msg(D_MsgKind_SelectTarget, .entity = d_handle_from_entity(entity)); + }break; + case D_MsgKind_SelectTarget: + { + D_Entity *entity = d_entity_from_handle(regs->entity); + if(entity->kind == D_EntityKind_Target) + { + D_EntityList all_targets = d_query_cached_entity_list_with_kind(D_EntityKind_Target); + B32 is_selected = !entity->disabled; + for(D_EntityNode *n = all_targets.first; n != 0; n = n->next) + { + D_Entity *target = n->entity; + d_entity_equip_disabled(target, 1); + } + if(!is_selected) + { + d_entity_equip_disabled(entity, 0); + } + } + }break; + case D_MsgKind_RetryEndedProcess: + { + D_Entity *ended_process = d_entity_from_handle(regs->entity); + D_Entity *target = d_entity_from_handle(ended_process->entity_handle); + if(target->kind == D_EntityKind_Target) + { + d_msg(D_MsgKind_LaunchAndRun, .entity = d_handle_from_entity(target)); + } + else if(d_entity_is_nil(target)) + { + log_user_errorf("The ended process' corresponding target is missing."); + } + else if(d_entity_is_nil(ended_process)) + { + log_user_errorf("Invalid ended process."); + } + }break; + + //- rjf: meta + case D_MsgKind_RegisterAsJITDebugger: + { +#if OS_WINDOWS + char filename_cstr[MAX_PATH] = {0}; + GetModuleFileName(0, filename_cstr, sizeof(filename_cstr)); + String8 debugger_binary_path = str8_cstring(filename_cstr); + String8 name8 = str8_lit("Debugger"); + String8 data8 = push_str8f(scratch.arena, "%S --jit_pid:%%ld --jit_code:%%ld --jit_addr:0x%%p", debugger_binary_path); + String16 name16 = str16_from_8(scratch.arena, name8); + String16 data16 = str16_from_8(scratch.arena, data8); + B32 likely_not_in_admin_mode = 0; + { + HKEY reg_key = 0; + LSTATUS status = 0; + status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\", 0, KEY_SET_VALUE, ®_key); + likely_not_in_admin_mode = (status == ERROR_ACCESS_DENIED); + status = RegSetValueExW(reg_key, (LPCWSTR)name16.str, 0, REG_SZ, (BYTE *)data16.str, data16.size*sizeof(U16)+2); + RegCloseKey(reg_key); + } + { + HKEY reg_key = 0; + LSTATUS status = 0; + status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\", 0, KEY_SET_VALUE, ®_key); + likely_not_in_admin_mode = (status == ERROR_ACCESS_DENIED); + status = RegSetValueExW(reg_key, (LPCWSTR)name16.str, 0, REG_SZ, (BYTE *)data16.str, data16.size*sizeof(U16)+2); + RegCloseKey(reg_key); + } + if(likely_not_in_admin_mode) + { + log_user_errorf("Could not register as the just-in-time debugger, access was denied; try running the debugger as administrator."); + } +#else + log_user_errorf("Registering as the just-in-time debugger is currently not supported on this system."); +#endif + }break; + case D_MsgKind_LogMarker: + { + log_infof("\"#MARKER\""); + }break; + } + } + } + arena_clear(d_state->msgs_arena); + MemoryZeroStruct(&d_state->msgs); + } + + ////////////////////////////// //- rjf: clear root level commands + // { arena_clear(d_state->root_cmd_arena); MemoryZeroStruct(&d_state->root_cmds); } + ////////////////////////////// //- rjf: autosave + // { d_state->seconds_til_autosave -= dt; if(d_state->seconds_til_autosave <= 0.f) @@ -6901,7 +7812,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } + ////////////////////////////// //- rjf: process top-level commands + // ProfScope("process top-level commands") { Temp scratch = scratch_begin(&arena, 1); @@ -8474,7 +9387,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) scratch_end(scratch); } + ////////////////////////////// //- rjf: unpack eval-dependent info + // D_Entity *process = d_entity_from_handle(d_regs()->process); D_Entity *thread = d_entity_from_handle(d_regs()->thread); Arch arch = d_arch_from_entity(thread); @@ -8527,7 +9442,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } + ////////////////////////////// //- rjf: build eval type context + // E_TypeCtx *type_ctx = push_array(arena, E_TypeCtx, 1); { E_TypeCtx *ctx = type_ctx; @@ -8539,7 +9456,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } e_select_type_ctx(type_ctx); + ////////////////////////////// //- rjf: build eval parse context + // E_ParseCtx *parse_ctx = push_array(arena, E_ParseCtx, 1); ProfScope("build eval parse context") { @@ -8557,7 +9476,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } e_select_parse_ctx(parse_ctx); + ////////////////////////////// //- rjf: build eval IR context + // E_IRCtx *ir_ctx = push_array(arena, E_IRCtx, 1); { E_IRCtx *ctx = ir_ctx; @@ -8642,7 +9563,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } e_select_ir_ctx(ir_ctx); + ////////////////////////////// //- rjf: build eval interpretation context + // E_InterpretCtx *interpret_ctx = push_array(arena, E_InterpretCtx, 1); { E_InterpretCtx *ctx = interpret_ctx; @@ -8659,9 +9582,11 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } e_select_interpret_ctx(interpret_ctx); + ////////////////////////////// //- rjf: compute state parameterization hash for ctrl runs, if ctrl is running - // if the hash doesn't match the one for the last run, we need to soft-halt and // re-send down the parameterization state + // if(d_ctrl_targets_running()) { U128 state_hash = d_hash_from_ctrl_param_state(); @@ -8671,7 +9596,9 @@ d_tick(Arena *arena, DI_Scope *di_scope, D_CmdList *cmds, F32 dt) } } - //- rjf: send messages + ////////////////////////////// + //- rjf: send messages to control + // if(d_state->ctrl_msgs.count != 0) { if(ctrl_u2c_push_msgs(&d_state->ctrl_msgs, os_now_microseconds()+100)) diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 17e6a5a1..a5570d9f 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -1565,7 +1565,7 @@ internal void d_msg_(D_MsgKind kind, D_Regs *regs); #define d_msg(kind, ...) d_msg_((kind),\ &(D_Regs)\ {\ -d_regs_lit_init_top\ +d_regs_lit_init_top \ __VA_ARGS__\ }) diff --git a/src/dbg_engine/generated/dbg_engine.meta.c b/src/dbg_engine/generated/dbg_engine.meta.c index f7d85569..978e28ba 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.c +++ b/src/dbg_engine/generated/dbg_engine.meta.c @@ -4,8 +4,9 @@ //- GENERATED CODE C_LINKAGE_BEGIN -Rng1U64 d_reg_slot_range_table[26] = +Rng1U64 d_reg_slot_range_table[28] = { +{OffsetOf(D_Regs, machine), OffsetOf(D_Regs, machine) + sizeof(D_Handle)}, {OffsetOf(D_Regs, module), OffsetOf(D_Regs, module) + sizeof(D_Handle)}, {OffsetOf(D_Regs, process), OffsetOf(D_Regs, process) + sizeof(D_Handle)}, {OffsetOf(D_Regs, thread), OffsetOf(D_Regs, thread) + sizeof(D_Handle)}, @@ -27,6 +28,7 @@ Rng1U64 d_reg_slot_range_table[26] = {OffsetOf(D_Regs, dbgi_key), OffsetOf(D_Regs, dbgi_key) + sizeof(DI_Key)}, {OffsetOf(D_Regs, vaddr_range), OffsetOf(D_Regs, vaddr_range) + sizeof(Rng1U64)}, {OffsetOf(D_Regs, voff_range), OffsetOf(D_Regs, voff_range) + sizeof(Rng1U64)}, +{OffsetOf(D_Regs, pid), OffsetOf(D_Regs, pid) + sizeof(U32)}, {OffsetOf(D_Regs, force_confirm), OffsetOf(D_Regs, force_confirm) + sizeof(B32)}, {OffsetOf(D_Regs, prefer_disasm), OffsetOf(D_Regs, prefer_disasm) + sizeof(B32)}, {OffsetOf(D_Regs, dir2), OffsetOf(D_Regs, dir2) + sizeof(Dir2)}, diff --git a/src/dbg_engine/generated/dbg_engine.meta.h b/src/dbg_engine/generated/dbg_engine.meta.h index d1b00360..42ac54ba 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.h +++ b/src/dbg_engine/generated/dbg_engine.meta.h @@ -8,6 +8,7 @@ typedef enum D_RegSlot { +D_RegSlot_Machine, D_RegSlot_Module, D_RegSlot_Process, D_RegSlot_Thread, @@ -29,6 +30,7 @@ D_RegSlot_Lines, D_RegSlot_DbgiKey, D_RegSlot_VaddrRange, D_RegSlot_VoffRange, +D_RegSlot_PID, D_RegSlot_ForceConfirm, D_RegSlot_PreferDisasm, D_RegSlot_Dir2, @@ -109,6 +111,7 @@ D_MsgKind_SelectTarget, D_MsgKind_RetryEndedProcess, D_MsgKind_RegisterAsJITDebugger, D_MsgKind_LogMarker, +D_MsgKind_COUNT, } D_MsgKind; typedef enum D_CfgSrc @@ -440,6 +443,7 @@ D_CmdParamSlot_COUNT, typedef struct D_Regs D_Regs; struct D_Regs { +D_Handle machine; D_Handle module; D_Handle process; D_Handle thread; @@ -461,6 +465,7 @@ D_LineList lines; DI_Key dbgi_key; Rng1U64 vaddr_range; Rng1U64 voff_range; +U32 pid; B32 force_confirm; B32 prefer_disasm; Dir2 dir2; @@ -497,6 +502,7 @@ U64 inline_depth; }; #define d_regs_lit_init_top \ +.machine = d_regs()->machine,\ .module = d_regs()->module,\ .process = d_regs()->process,\ .thread = d_regs()->thread,\ @@ -518,6 +524,7 @@ U64 inline_depth; .dbgi_key = d_regs()->dbgi_key,\ .vaddr_range = d_regs()->vaddr_range,\ .voff_range = d_regs()->voff_range,\ +.pid = d_regs()->pid,\ .force_confirm = d_regs()->force_confirm,\ .prefer_disasm = d_regs()->prefer_disasm,\ .dir2 = d_regs()->dir2,\ @@ -563,7 +570,7 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = {&DEV_updating_indicator, str8_lit_comp("updating_indicator")}, }; C_LINKAGE_BEGIN -extern Rng1U64 d_reg_slot_range_table[26]; +extern Rng1U64 d_reg_slot_range_table[28]; extern String8 d_msg_kind_name_lower_table[71]; extern Rng1U64 d_cmd_param_slot_range_table[23]; extern String8 d_entity_kind_display_string_table[31]; diff --git a/src/dbg_frontend/dbg_frontend.mdesk b/src/dbg_frontend/dbg_frontend.mdesk index 3036ce49..80895bb4 100644 --- a/src/dbg_frontend/dbg_frontend.mdesk +++ b/src/dbg_frontend/dbg_frontend.mdesk @@ -112,7 +112,8 @@ DF_MsgKindTable: @enum DF_MsgKind: { - @expand(DF_MsgKindTable a) `$(a.name)` + @expand(DF_MsgKindTable a) `$(a.name)`, + COUNT } @data(String8) df_msg_kind_name_lower_table: diff --git a/src/dbg_frontend/dbg_frontend_core.c b/src/dbg_frontend/dbg_frontend_core.c index c9927761..1b2b19b8 100644 --- a/src/dbg_frontend/dbg_frontend_core.c +++ b/src/dbg_frontend/dbg_frontend_core.c @@ -7809,6 +7809,19 @@ df_request_frame(void) df_state->num_frames_requested = 4; } +//////////////////////////////// +//~ rjf: Message Functions + +internal void +df_msg_(DF_MsgKind kind, D_Regs *regs) +{ + DF_MsgNode *n = push_array(df_state->msgs_arena, DF_MsgNode, 1); + SLLQueuePush(df_state->msgs.first, df_state->msgs.last, n); + df_state->msgs.count += 1; + n->v.kind = kind; + n->v.regs = d_regs_copy(df_state->msgs_arena, regs); +} + //////////////////////////////// //~ rjf: Main Layer Top-Level Calls @@ -10601,9 +10614,12 @@ df_end_frame(void) } internal void -df_frame(Arena *arena, D_CmdList *cmds) +df_frame(D_CmdList *cmds, F32 dt) { - df_begin_frame(arena, cmds); + Temp scratch = scratch_begin(0, 0); + DI_Scope *di_scope = di_scope_open(); + d_tick(scratch.arena, di_scope, cmds, dt); + df_begin_frame(scratch.arena, cmds); { B32 queue_drag_drop = 0; if(queue_drag_drop) @@ -10620,7 +10636,7 @@ df_frame(Arena *arena, D_CmdList *cmds) } d_push_regs(); d_regs()->window = df_handle_from_window(w); - df_window_update_and_render(arena, w, cmds); + df_window_update_and_render(scratch.arena, w, cmds); D_Regs *window_regs = d_pop_regs(); if(df_window_from_handle(last_focused_window) == w) { @@ -10644,4 +10660,7 @@ df_frame(Arena *arena, D_CmdList *cmds) } r_end_frame(); } + + di_scope_close(di_scope); + scratch_end(scratch); } diff --git a/src/dbg_frontend/dbg_frontend_core.h b/src/dbg_frontend/dbg_frontend_core.h index df2ac65f..41efffd1 100644 --- a/src/dbg_frontend/dbg_frontend_core.h +++ b/src/dbg_frontend/dbg_frontend_core.h @@ -365,6 +365,31 @@ struct DF_ViewRuleSpec #include "generated/dbg_frontend.meta.h" +//////////////////////////////// +//~ rjf: Message Types + +typedef struct DF_Msg DF_Msg; +struct DF_Msg +{ + DF_MsgKind kind; + D_Regs *regs; +}; + +typedef struct DF_MsgNode DF_MsgNode; +struct DF_MsgNode +{ + DF_MsgNode *next; + DF_Msg v; +}; + +typedef struct DF_MsgList DF_MsgList; +struct DF_MsgList +{ + DF_MsgNode *first; + DF_MsgNode *last; + U64 count; +}; + //////////////////////////////// //~ rjf: Theme Types @@ -583,6 +608,10 @@ struct DF_State // rjf: arenas Arena *arena; + // rjf: messages + Arena *msgs_arena; + DF_MsgList msgs; + // rjf: frame request state U64 num_frames_requested; @@ -922,7 +951,13 @@ internal void df_request_frame(void); //////////////////////////////// //~ rjf: Message Functions - +internal void df_msg_(DF_MsgKind kind, D_Regs *regs); +#define df_msg(kind, ...) df_msg_((kind),\ +&(D_Regs)\ +{\ +d_regs_lit_init_top\ +__VA_ARGS__\ +}) //////////////////////////////// //~ rjf: Main Layer Top-Level Calls @@ -930,6 +965,6 @@ internal void df_request_frame(void); internal void df_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, D_StateDeltaHistory *hist); internal void df_begin_frame(Arena *arena, D_CmdList *cmds); internal void df_end_frame(void); -internal void df_frame(Arena *arena, D_CmdList *cmds); +internal void df_frame(D_CmdList *cmds, F32 dt); #endif // DBG_FRONTEND_CORE_H diff --git a/src/dbg_frontend/generated/dbg_frontend.meta.h b/src/dbg_frontend/generated/dbg_frontend.meta.h index ef1ddc9d..f1cd33a6 100644 --- a/src/dbg_frontend/generated/dbg_frontend.meta.h +++ b/src/dbg_frontend/generated/dbg_frontend.meta.h @@ -69,6 +69,7 @@ DF_MsgKind_FindThread, DF_MsgKind_FindSelectedThread, DF_MsgKind_GoToName, DF_MsgKind_FindCodeLocation, +DF_MsgKind_COUNT, } DF_MsgKind; typedef enum DF_IconKind diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index 3105d8f1..d435fdf9 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -9,7 +9,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DI_Scope *di_scope = di_scope_open(); ////////////////////////////// //- rjf: begin logging @@ -27,7 +26,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) log_scope_begin(); ////////////////////////////// - //- rjf: mark user-facing tick + //- rjf: mark user-facing thread tick // ProfTick(0); txt_user_clock_tick(); @@ -35,6 +34,15 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) geo_user_clock_tick(); tex_user_clock_tick(); + ////////////////////////////// + //- rjf: get events from the OS + // + OS_EventList events = {0}; + if(os_handle_match(repaint_window_handle, os_handle_zero())) + { + events = os_get_events(scratch.arena, df_state->num_frames_requested == 0); + } + ////////////////////////////// //- rjf: pick target hz // @@ -78,15 +86,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) // F32 dt = 1.f/target_hz; - ////////////////////////////// - //- rjf: get events from the OS - // - OS_EventList events = {0}; - if(os_handle_match(repaint_window_handle, os_handle_zero())) - { - events = os_get_events(scratch.arena, df_state->num_frames_requested == 0); - } - ////////////////////////////// //- rjf: begin measuring actual per-frame work // @@ -264,10 +263,9 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) D_CmdList cmds = d_gather_root_cmds(scratch.arena); ////////////////////////////// - //- rjf: tick debug engine; do frontend frame + //- rjf: do frontend frame // - d_tick(scratch.arena, di_scope, &cmds, dt); - df_frame(scratch.arena, &cmds); + df_frame(&cmds, dt); ////////////////////////////// //- rjf: show windows after first frame @@ -309,7 +307,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) } } - di_scope_close(di_scope); scratch_end(scratch); ProfEnd(); }