diff --git a/project.4coder b/project.4coder index 40c41a21..1ff38098 100644 --- a/project.4coder +++ b/project.4coder @@ -49,7 +49,7 @@ commands = // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: [raddbg wsl] // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/artifact_cache/artifact_cache.c b/src/artifact_cache/artifact_cache.c index 53abac40..b5920e6c 100644 --- a/src/artifact_cache/artifact_cache.c +++ b/src/artifact_cache/artifact_cache.c @@ -422,12 +422,13 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - // rjf: eliminate existing values, if nay - if(cache->destroy && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) + // rjf: eliminate existing values, if any, if they do not match the current + if(!MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) { if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0)) { cache->destroy(n->val); + MemoryZeroStruct(&n->val); break; } cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64); @@ -543,12 +544,13 @@ ac_async_tick(void) { if(str8_match(n->key, r->key, 0)) { - // rjf: eliminate existing values, if nay - if(cache->destroy && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) + // rjf: eliminate existing values, if any, if they do not match the current + if(!MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;) { if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0)) { cache->destroy(n->val); + MemoryZeroStruct(&n->val); break; } cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64); diff --git a/src/dbg_engine/dbg_engine_ctrl.c b/src/dbg_engine/dbg_engine_ctrl.c index 1e821a25..d33b1f5d 100644 --- a/src/dbg_engine/dbg_engine_ctrl.c +++ b/src/dbg_engine/dbg_engine_ctrl.c @@ -288,7 +288,7 @@ internal void d_msg_deep_copy(Arena *arena, D_Msg *dst, D_Msg *src) { MemoryCopyStruct(dst, src); - dst->path = push_str8_copy(arena, src->path); + dst->path = str8_copy(arena, src->path); dst->entry_points = str8_list_copy(arena, &src->entry_points); dst->cmd_line_string_list = str8_list_copy(arena, &src->cmd_line_string_list); dst->env_string_list = str8_list_copy(arena, &src->env_string_list); diff --git a/src/dbg_engine/dbg_engine_user.c b/src/dbg_engine/dbg_engine_user.c index 9c9712ff..5cc0be1f 100644 --- a/src/dbg_engine/dbg_engine_user.c +++ b/src/dbg_engine/dbg_engine_user.c @@ -169,10 +169,13 @@ d_cmd_params_copy(Arena *arena, D_CmdParams *src) for(U64 idx = 0; idx < dst.targets.count; idx += 1) { D_Target *target = &dst.targets.v[idx]; - target->exe = push_str8_copy(arena, target->exe); - target->args = push_str8_copy(arena, target->args); - target->working_directory = push_str8_copy(arena, target->working_directory); - target->custom_entry_point_name = push_str8_copy(arena, target->custom_entry_point_name); + target->exe = str8_copy(arena, target->exe); + target->args = str8_copy(arena, target->args); + target->working_directory = str8_copy(arena, target->working_directory); + target->custom_entry_point_name = str8_copy(arena, target->custom_entry_point_name); + target->stdout_path = str8_copy(arena, target->stdout_path); + target->stderr_path = str8_copy(arena, target->stderr_path); + target->stdin_path = str8_copy(arena, target->stdin_path); target->env = str8_list_copy(arena, &target->env); } return dst; @@ -739,6 +742,105 @@ d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread) return result; } +internal D_TrapNet +d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread) +{ + D_TrapNet result = {0}; + { + U64 read_endt_us = now_time_us() + 1000000; + Temp scratch = scratch_begin(&arena, 1); + Access *access = access_open(); + D_EntityCtx *entity_ctx = &d_user_state->ctrl_entity_store->ctx; + + // rjf: unpack thread + Arch arch = thread->arch; + U64 ip_vaddr = d_rip_from_thread(entity_ctx, thread->handle); + D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); + D_Entity *module = d_module_from_process_vaddr(process, ip_vaddr); + DI_Key dbgi_key = d_dbgi_key_from_module(module); + + // rjf: ip => enclosing scope's list(voff_range) + Rng1U64List scope_voff_rngs = {0}; + { + U64 ip_voff = d_voff_from_vaddr(module, ip_vaddr); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0); + if(rdi != &rdi_parsed_nil) + { + result.good_line_info = 1; + RDI_Scope *scope = rdi_scope_from_voff(rdi, ip_voff); + U64 all_scope_voffs_count = 0; + U64 *all_scope_voffs = rdi_table_from_name(rdi, ScopeVOffData, &all_scope_voffs_count); + for(U64 voff_idx = scope->voff_range_first; voff_idx+1 < scope->voff_range_opl; voff_idx += 1) + { + Rng1U64 voff_range = r1u64(all_scope_voffs[voff_idx], all_scope_voffs[voff_idx+1]); + rng1u64_list_push(scratch.arena, &scope_voff_rngs, voff_range); + } + } + } + + // rjf: place traps at all possible exit points of all scope's ranges + for EachNode(n, Rng1U64Node, scope_voff_rngs.first) + { + Rng1U64 voff_range = n->v; + Rng1U64 vaddr_range = d_vaddr_range_from_voff_range(module, voff_range); + D_ProcessMemorySlice code_slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, vaddr_range, 0, read_endt_us); + if(!code_slice.any_byte_bad) + { + String8 code = code_slice.data; + DASM_CtrlFlowInfo ctrl_flow_info = dasm_ctrl_flow_info_from_arch_vaddr_code(scratch.arena, DASM_InstFlag_Branch|DASM_InstFlag_UnconditionalJump|DASM_InstFlag_Return, arch, vaddr_range.min, code); + + // rjf: add traps at all jump destinations which do *not* fall into any of the scope's ranges + for EachNode(exit_pt_n, DASM_CtrlFlowPointNode, ctrl_flow_info.exit_points.first) + { + U64 jump_dest_vaddr = exit_pt_n->v.jump_dest_vaddr; + B32 jump_dest_vaddr_is_out_of_scope = 1; + for EachNode(scope_n, Rng1U64Node, scope_voff_rngs.first) + { + if(contains_1u64(scope_n->v, jump_dest_vaddr)) + { + jump_dest_vaddr_is_out_of_scope = 0; + break; + } + } + if(jump_dest_vaddr_is_out_of_scope) + { + D_Trap trap = {D_TrapFlag_EndStepping|D_TrapFlag_IgnoreStackPointerCheck, jump_dest_vaddr}; + d_trap_list_push(arena, &result.traps, &trap); + } + } + + // rjf: add trap at natural exit point of scope + { + U64 opl_vaddr = vaddr_range.max; + B32 opl_vaddr_is_out_of_scope = 1; + for EachNode(scope_n, Rng1U64Node, scope_voff_rngs.first) + { + if(contains_1u64(scope_n->v, opl_vaddr)) + { + opl_vaddr_is_out_of_scope = 0; + break; + } + } + if(opl_vaddr_is_out_of_scope) + { + D_Trap trap = {D_TrapFlag_EndStepping|D_TrapFlag_IgnoreStackPointerCheck, opl_vaddr}; + d_trap_list_push(arena, &result.traps, &trap); + } + } + } + else + { + result.good_read = 0; + break; + } + } + + access_close(access); + scratch_end(scratch); + } + return result; +} + //////////////////////////////// //~ rjf: Debug Info Lookups @@ -1684,11 +1786,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { D_Msg *msg = d_msg_list_push(scratch.arena, &ctrl_msgs); msg->kind = D_MsgKind_Launch; - msg->path = working_directory; - msg->cmd_line_string_list = cmdln_strings; - msg->stdout_path = stdout_path; - msg->stderr_path = stderr_path; - msg->stdin_path = stdin_path; + msg->path = str8_copy(scratch.arena, working_directory); + msg->cmd_line_string_list = str8_list_copy(scratch.arena, &cmdln_strings); + msg->stdout_path = str8_copy(scratch.arena, stdout_path); + msg->stderr_path = str8_copy(scratch.arena, stderr_path); + msg->stdin_path = str8_copy(scratch.arena, stdin_path); msg->debug_subprocesses = target->debug_subprocesses; msg->env_inherit = 1; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); @@ -1807,6 +1909,9 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_StepOverInst: {trap_net = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break; case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break; case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; +#if 0 + case D_CmdKind_StepOut: {trap_net = d_trap_net_from_thread__step_out_scope(scratch.arena, thread);}break; +#else case D_CmdKind_StepOut: { Access *access = access_open(); @@ -1830,6 +1935,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P access_close(access); }break; +#endif } B32 good_trap_net = (trap_net.good_read || !trap_net.good_line_info); if(good_trap_net && trap_net.traps.count != 0) diff --git a/src/dbg_engine/dbg_engine_user.h b/src/dbg_engine/dbg_engine_user.h index cad43e6d..306de1a2 100644 --- a/src/dbg_engine/dbg_engine_user.h +++ b/src/dbg_engine/dbg_engine_user.h @@ -422,6 +422,7 @@ internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, D_Entity *thread); internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, D_Entity *thread); internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, D_Entity *thread); +internal D_TrapNet d_trap_net_from_thread__step_out_scope(Arena *arena, D_Entity *thread); //////////////////////////////// //~ rjf: Debug Info Lookups diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 440a465d..e5b2b359 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10488,9 +10488,14 @@ rd_frame(void) ////////////////////////////// //- rjf: do per-frame resets // - arena_clear(rd_frame_arena()); - rd_state->top_regs = &rd_state->base_regs; - rd_regs_copy_contents(rd_frame_arena(), &rd_state->top_regs->v, &rd_state->top_regs->v); + { + Temp scratch = scratch_begin(0, 0); + rd_state->top_regs = &rd_state->base_regs; + rd_regs_copy_contents(scratch.arena, &rd_state->top_regs->v, &rd_state->top_regs->v); + arena_clear(rd_frame_arena()); + rd_regs_copy_contents(rd_frame_arena(), &rd_state->top_regs->v, &rd_state->top_regs->v); + scratch_end(scratch); + } if(rd_state->next_hover_regs != 0) { rd_state->hover_regs = rd_regs_copy(rd_frame_arena(), rd_state->next_hover_regs); diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index e129dfc5..b04dd7e5 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -10,6 +10,13 @@ // [ ] memory_size(...) view for quickly evaluating memory sizes // [ ] value coloring view in watch window, so you can quickly scroll & see values outside of a threshold // +// [ ] asan pass +// [ ] policy for closing debug info which is no longer relevant? +// [ ] codebase-internal barrier impl (win7/linux support) +// [ ] external window focusing bugs +// [ ] PDB -> RDI conversion memory usage +// [x] killing/restarting thread performance (#780) +// // [ ] project/user file improvements // [ ] "default" -> "untitled" // [ ] should clear default project data every time the program starts @@ -18,12 +25,6 @@ // [ ] more things should move to user data, but project-tagged - like // recent files, watches?, etc. // -// [ ] killing/restarting thread performance (#780) -// [ ] codebase-internal barrier impl (win7/linux support) -// [ ] PDB -> RDI conversion memory usage -// [ ] policy for closing debug info which is no longer relevant? -// [ ] external window focusing bugs -// // [ ] linux/dwarf fixes // [ ] excessive CPU usage on async threads - barrier impl? // [ ] step-over/step-into doesn't step successfully in many cases, just causes a continue diff --git a/src/text/text.c b/src/text/text.c index b2ec582d..759443b7 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -2944,12 +2944,13 @@ txt_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_ou shared->artifact->info = shared->info; } lane_sync(); + AC_Artifact result = {0}; + result.u64[0] = (U64)shared->artifact; + lane_sync(); access_close(access); scratch_end(scratch); ProfEnd(); - AC_Artifact result = {0}; - result.u64[0] = (U64)shared->artifact; return result; }