From c7da3e8a13fb47ffb046bffb8cfe84d7d65ffe4c Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 21 Feb 2025 08:42:33 -0800 Subject: [PATCH] distinguish cfg (breakpoints, watch pins) source-locations from address locations; expand breakpoint addresses to being full expressions, & use this to implement symbol breakpoints (we now support fancier address resolution breakpoints too) --- src/ctrl/ctrl_core.c | 354 ++++++++++++++++------------- src/ctrl/ctrl_core.h | 24 +- src/dbg_engine/dbg_engine_core.c | 24 +- src/dbg_engine/dbg_engine_core.h | 3 +- src/raddbg/generated/raddbg.meta.c | 12 +- src/raddbg/generated/raddbg.meta.h | 2 +- src/raddbg/raddbg.mdesk | 24 +- src/raddbg/raddbg_core.c | 168 ++++++-------- src/raddbg/raddbg_core.h | 3 +- src/raddbg/raddbg_views.c | 10 +- src/raddbg/raddbg_widgets.c | 14 +- 11 files changed, 335 insertions(+), 303 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index ee778ba6..ff10a7d6 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3418,11 +3418,11 @@ ctrl_thread__entry_point(void *p) //- rjf: breakpoint resolution internal void -ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { if(user_bps->first == 0) { return; } Temp scratch = scratch_begin(&arena, 1); - DI_Scope *di_scope = di_scope_open(); + DI_Scope *di_scope = eval_scope->di_scope; CTRL_Entity *module_entity = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, module); CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp}; @@ -3486,45 +3486,37 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_Handle proc } }break; - //- rjf: symbol:voff-based breakpoints - case CTRL_UserBreakpointKind_SymbolNameAndOffset: + //- rjf: expression-based breakpoints + case CTRL_UserBreakpointKind_Expression: { - String8 symbol_name = bp->string; - U64 voff = bp->u64; - RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); - RDI_ParsedNameMap map = {0}; - rdi_parsed_from_name_map(rdi, mapptr, &map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, symbol_name.str, symbol_name.size); - if(node != 0) + String8 expr = bp->string; + E_Value value = e_value_from_string(expr); + if(value.u64 != 0) { - U32 id_count = 0; - U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); - for(U32 match_i = 0; match_i < id_count; match_i += 1) - { - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, ids[match_i]); - U64 proc_voff = rdi_first_voff_from_procedure(rdi, procedure); - U64 proc_vaddr = proc_voff + base_vaddr; - DMN_Trap trap = {process.dmn_handle, proc_vaddr + voff, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); - } + DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); } }break; } } - di_scope_close(di_scope); scratch_end(scratch); } internal void -ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { CTRL_UserBreakpoint *bp = &n->v; - if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) + if(bp->kind == CTRL_UserBreakpointKind_Expression) { - DMN_Trap trap = {process.dmn_handle, bp->u64, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + String8 expr = bp->string; + E_Value value = e_value_from_string(expr); + if(value.u64 != 0) + { + DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } } } } @@ -4497,6 +4489,128 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) return result; } +//- rjf: control thread eval scopes + +internal CTRL_EvalScope * +ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread) +{ + CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1); + scope->di_scope = di_scope_open(); + + // rjf: unpack thread + Arch arch = thread->arch; + U64 thread_rip_vaddr = dmn_rip_from_thread(thread->handle.dmn_handle); + CTRL_Entity *process = ctrl_process_from_entity(thread); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); + U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); + + // rjf: gather evaluation modules + U64 eval_modules_count = Max(1, ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module]); + E_Module *eval_modules = push_array(arena, E_Module, eval_modules_count); + E_Module *eval_modules_primary = &eval_modules[0]; + eval_modules_primary->rdi = &di_rdi_parsed_nil; + eval_modules_primary->vaddr_range = r1u64(0, max_U64); + { + U64 eval_module_idx = 0; + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) + { + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; + process != &ctrl_entity_nil; + process = process->next) + { + if(process->kind != CTRL_EntityKind_Process) { continue; } + for(CTRL_Entity *mod = process->first; + mod != &ctrl_entity_nil; + mod = mod->next) + { + if(mod->kind != CTRL_EntityKind_Module) { continue; } + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + eval_modules[eval_module_idx].arch = arch; + eval_modules[eval_module_idx].rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, max_U64); + eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; + eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); + eval_modules[eval_module_idx].space.u64_0 = (U64)process; + if(mod == module) + { + eval_modules_primary = &eval_modules[eval_module_idx]; + } + eval_module_idx += 1; + } + } + } + } + + // rjf: build eval type context + { + E_TypeCtx *ctx = &scope->type_ctx; + ctx->ip_vaddr = thread_rip_vaddr; + ctx->ip_voff = thread_rip_voff; + ctx->modules = eval_modules; + ctx->modules_count = eval_modules_count; + ctx->primary_module = eval_modules_primary; + } + e_select_type_ctx(&scope->type_ctx); + + // rjf: build eval parse context + ProfScope("build eval parse context") + { + E_ParseCtx *ctx = &scope->parse_ctx; + ctx->ip_vaddr = thread_rip_vaddr; + ctx->ip_voff = thread_rip_voff; + ctx->ip_thread_space = e_space_make(CTRL_EvalSpaceKind_Entity); + ctx->ip_thread_space.u64_0 = (U64)thread; + ctx->modules = eval_modules; + ctx->modules_count = eval_modules_count; + ctx->primary_module = eval_modules_primary; + ctx->regs_map = ctrl_string2reg_from_arch(arch); + ctx->reg_alias_map = ctrl_string2alias_from_arch(arch); + ctx->locals_map = e_push_locals_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); + ctx->member_map = e_push_member_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); + } + e_select_parse_ctx(&scope->parse_ctx); + + // rjf: build eval IR context + { + E_IRCtx *ctx = &scope->ir_ctx; + ctx->macro_map = push_array(arena, E_String2ExprMap, 1); + ctx->macro_map[0] = e_string2expr_map_make(arena, 512); + ctx->lookup_rule_map = push_array(arena, E_LookupRuleMap, 1); + ctx->lookup_rule_map[0] = e_lookup_rule_map_make(arena, 512); + ctx->irgen_rule_map = push_array(arena, E_IRGenRuleMap, 1); + ctx->irgen_rule_map[0] = e_irgen_rule_map_make(arena, 512); + ctx->auto_hook_map = push_array(arena, E_AutoHookMap, 1); + ctx->auto_hook_map[0] = e_auto_hook_map_make(arena, 512); + } + e_select_ir_ctx(&scope->ir_ctx); + + // rjf: build eval interpretation context + { + E_InterpretCtx *ctx = &scope->interpret_ctx; + ctx->space_rw_user_data = ctrl_state->ctrl_thread_entity_store; + ctx->space_read = ctrl_eval_space_read; + ctx->primary_space = eval_modules_primary->space; + ctx->reg_arch = eval_modules_primary->arch; + ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); + ctx->reg_space.u64_0 = (U64)thread; + ctx->module_base = push_array(arena, U64, 1); + ctx->module_base[0]= module->vaddr_range.min; + ctx->tls_base = push_array(arena, U64, 1); + } + e_select_interpret_ctx(&scope->interpret_ctx); + + return scope; +} + +internal void +ctrl_thread__eval_scope_end(CTRL_EvalScope *scope) +{ + di_scope_close(scope->di_scope); +} + //- rjf: log flusher internal void @@ -4828,25 +4942,30 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: gather all initial breakpoints // DMN_TrapChunkList user_traps = {0}; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; - machine != &ctrl_entity_nil; - machine = machine->next) { - if(machine->kind != CTRL_EntityKind_Machine) { continue; } - for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) + CTRL_Entity *thread = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, target_thread); + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread); + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { - if(process->kind != CTRL_EntityKind_Process) { continue; } - - // rjf: resolve module-dependent user bps - for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - if(module->kind != CTRL_EntityKind_Module) { continue; } - ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, process->handle, module->handle, &msg->user_bps, &user_traps); + if(process->kind != CTRL_EntityKind_Process) { continue; } + + // rjf: resolve module-dependent user bps + for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + { + if(module->kind != CTRL_EntityKind_Module) { continue; } + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, eval_scope, process->handle, module->handle, &msg->user_bps, &user_traps); + } + + // rjf: push virtual-address user breakpoints per-process + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, eval_scope, process->handle, &msg->user_bps, &user_traps); } - - // rjf: push virtual-address user breakpoints per-process - ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, process->handle, &msg->user_bps, &user_traps); } + ctrl_thread__eval_scope_end(eval_scope); } ////////////////////////////// @@ -5110,39 +5229,48 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) }break; case DMN_EventKind_CreateProcess: { - DMN_TrapChunkList new_traps = {0}; - ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, ctrl_handle_make(CTRL_MachineID_Local, event->process), &msg->user_bps, &new_traps); - log_infof("step_rule: create_process -> resolve traps\n"); - log_infof("new_traps:\n{\n"); - for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &ctrl_entity_nil); { - for(U64 idx = 0; idx < n->count; idx += 1) + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), &msg->user_bps, &new_traps); + log_infof("step_rule: create_process -> resolve traps\n"); + log_infof("new_traps:\n{\n"); + for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) { - DMN_Trap *trap = &n->v[idx]; - log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + for(U64 idx = 0; idx < n->count; idx += 1) + { + DMN_Trap *trap = &n->v[idx]; + log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + } } + log_infof("}\n\n"); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); } - log_infof("}\n\n"); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + ctrl_thread__eval_scope_end(eval_scope); }break; case DMN_EventKind_LoadModule: { - DMN_TrapChunkList new_traps = {0}; - ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, ctrl_handle_make(CTRL_MachineID_Local, event->process), ctrl_handle_make(CTRL_MachineID_Local, event->module), &msg->user_bps, &new_traps); - log_infof("step_rule: load_module -> resolve traps\n"); - log_infof("new_traps:\n{\n"); - for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) + CTRL_Entity *thread = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->thread)); + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread); { - for(U64 idx = 0; idx < n->count; idx += 1) + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), ctrl_handle_make(CTRL_MachineID_Local, event->module), &msg->user_bps, &new_traps); + log_infof("step_rule: load_module -> resolve traps\n"); + log_infof("new_traps:\n{\n"); + for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) { - DMN_Trap *trap = &n->v[idx]; - log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + for(U64 idx = 0; idx < n->count; idx += 1) + { + DMN_Trap *trap = &n->v[idx]; + log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + } } + log_infof("}\n\n"); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); } - log_infof("}\n\n"); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + ctrl_thread__eval_scope_end(eval_scope); }break; } @@ -5463,107 +5591,9 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) ProfScope("evaluate hit stop conditions") { - DI_Scope *di_scope = di_scope_open(); - - // rjf: gather evaluation modules - U64 eval_modules_count = Max(1, ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module]); - E_Module *eval_modules = push_array(temp.arena, E_Module, eval_modules_count); - E_Module *eval_modules_primary = &eval_modules[0]; - eval_modules_primary->rdi = &di_rdi_parsed_nil; - eval_modules_primary->vaddr_range = r1u64(0, max_U64); - { - U64 eval_module_idx = 0; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; - machine != &ctrl_entity_nil; - machine = machine->next) - { - if(machine->kind != CTRL_EntityKind_Machine) { continue; } - for(CTRL_Entity *process = machine->first; - process != &ctrl_entity_nil; - process = process->next) - { - if(process->kind != CTRL_EntityKind_Process) { continue; } - for(CTRL_Entity *mod = process->first; - mod != &ctrl_entity_nil; - mod = mod->next) - { - if(mod->kind != CTRL_EntityKind_Module) { continue; } - CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; - eval_modules[eval_module_idx].arch = arch; - eval_modules[eval_module_idx].rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); - eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; - eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); - eval_modules[eval_module_idx].space.u64_0 = (U64)process; - if(mod == module) - { - eval_modules_primary = &eval_modules[eval_module_idx]; - } - eval_module_idx += 1; - } - } - } - } - - // rjf: loop through all conditions, check all + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(temp.arena, thread); for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { - // rjf: build eval type context - E_TypeCtx type_ctx = zero_struct; - { - E_TypeCtx *ctx = &type_ctx; - ctx->ip_vaddr = thread_rip_vaddr; - ctx->ip_voff = thread_rip_voff; - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - } - e_select_type_ctx(&type_ctx); - - // rjf: build eval parse context - E_ParseCtx parse_ctx = zero_struct; - ProfScope("build eval parse context") - { - E_ParseCtx *ctx = &parse_ctx; - ctx->ip_vaddr = thread_rip_vaddr; - ctx->ip_voff = thread_rip_voff; - ctx->ip_thread_space = e_space_make(CTRL_EvalSpaceKind_Entity); - ctx->ip_thread_space.u64_0 = (U64)thread; - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - ctx->regs_map = ctrl_string2reg_from_arch(arch); - ctx->reg_alias_map = ctrl_string2alias_from_arch(arch); - ctx->locals_map = e_push_locals_map_from_rdi_voff(temp.arena, eval_modules_primary->rdi, thread_rip_voff); - ctx->member_map = e_push_member_map_from_rdi_voff(temp.arena, eval_modules_primary->rdi, thread_rip_voff); - } - e_select_parse_ctx(&parse_ctx); - - // rjf: build eval IR context - E_IRCtx ir_ctx = zero_struct; - { - E_IRCtx *ctx = &ir_ctx; - ctx->macro_map = push_array(temp.arena, E_String2ExprMap, 1); - ctx->macro_map[0] = e_string2expr_map_make(temp.arena, 512); - } - e_select_ir_ctx(&ir_ctx); - - // rjf: build eval interpretation context - E_InterpretCtx interpret_ctx = zero_struct; - { - E_InterpretCtx *ctx = &interpret_ctx; - ctx->space_rw_user_data = ctrl_state->ctrl_thread_entity_store; - ctx->space_read = ctrl_eval_space_read; - ctx->primary_space = eval_modules_primary->space; - ctx->reg_arch = eval_modules_primary->arch; - ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); - ctx->reg_space.u64_0 = (U64)thread; - ctx->module_base = push_array(temp.arena, U64, 1); - ctx->module_base[0]= module->vaddr_range.min; - ctx->tls_base = push_array(temp.arena, U64, 1); - } - e_select_interpret_ctx(&interpret_ctx); - // rjf: evaluate E_Eval eval = zero_struct; ProfScope("evaluate expression") @@ -5586,7 +5616,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) break; } } - di_scope_close(di_scope); + ctrl_thread__eval_scope_end(eval_scope); } // rjf: gather trap net hits diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index c21f5394..1102c178 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -263,8 +263,7 @@ typedef enum CTRL_UserBreakpointKind { CTRL_UserBreakpointKind_Null, CTRL_UserBreakpointKind_FileNameAndLineColNumber, - CTRL_UserBreakpointKind_SymbolNameAndOffset, - CTRL_UserBreakpointKind_VirtualAddress, + CTRL_UserBreakpointKind_Expression, CTRL_UserBreakpointKind_COUNT } CTRL_UserBreakpointKind; @@ -636,6 +635,19 @@ struct CTRL_DbgDirNode U64 module_direct_count; }; +//////////////////////////////// +//~ rjf: Control Thread Evaluation Scopes + +typedef struct CTRL_EvalScope CTRL_EvalScope; +struct CTRL_EvalScope +{ + DI_Scope *di_scope; + E_TypeCtx type_ctx; + E_ParseCtx parse_ctx; + E_IRCtx ir_ctx; + E_InterpretCtx interpret_ctx; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -933,8 +945,8 @@ 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_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); -internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); //- rjf: module lifetime open/close work internal void ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_range, String8 path); @@ -946,6 +958,10 @@ internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ //- rjf: eval helpers internal B32 ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 vaddr_range); +//- rjf: control thread eval scopes +internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread); +internal void ctrl_thread__eval_scope_end(CTRL_EvalScope *scope); + //- rjf: log flusher internal void ctrl_thread__flush_info_log(String8 string); internal void ctrl_thread__end_and_flush_info_log(void); diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index a3f72a26..0c51c544 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -61,7 +61,7 @@ d_breakpoint_array_copy(Arena *arena, D_BreakpointArray *src) for(U64 idx = 0; idx < dst.count; idx += 1) { dst.v[idx].file_path = push_str8_copy(arena, dst.v[idx].file_path); - dst.v[idx].symbol_name = push_str8_copy(arena, dst.v[idx].symbol_name); + dst.v[idx].vaddr_expr = push_str8_copy(arena, dst.v[idx].vaddr_expr); dst.v[idx].condition = push_str8_copy(arena, dst.v[idx].condition); } return dst; @@ -1902,8 +1902,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P D_Breakpoint *bp = &breakpoints->v[idx]; str8_list_push(scratch.arena, &strings, bp->file_path); str8_list_push(scratch.arena, &strings, str8_struct(&bp->pt)); - str8_list_push(scratch.arena, &strings, bp->symbol_name); - str8_list_push(scratch.arena, &strings, str8_struct(&bp->vaddr)); + str8_list_push(scratch.arena, &strings, bp->vaddr_expr); str8_list_push(scratch.arena, &strings, bp->condition); } } @@ -2248,7 +2247,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P } else if(params->vaddr != 0) { - run_extra_bps.v[0].vaddr = params->vaddr; + run_extra_bps.v[0].vaddr_expr = push_str8f(scratch.arena, "0x%I64x", params->vaddr); } d_cmd(D_CmdKind_Run); }break; @@ -2418,20 +2417,11 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P } } - // rjf: virtual address location -> add breakpoint for address - else if(bp->vaddr != 0) + // rjf: virtual address expression -> add expression breakpoint + else if(bp->vaddr_expr.size != 0) { - CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_VirtualAddress}; - ctrl_user_bp.u64 = bp->vaddr; - ctrl_user_bp.condition = bp->condition; - ctrl_user_breakpoint_list_push(scratch.arena, &msg->user_bps, &ctrl_user_bp); - } - - // rjf: symbol name location -> add breakpoint for symbol name - else if(bp->symbol_name.size != 0) - { - CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_SymbolNameAndOffset}; - ctrl_user_bp.string = bp->symbol_name; + CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_Expression}; + ctrl_user_bp.string = bp->vaddr_expr; ctrl_user_bp.condition = bp->condition; ctrl_user_breakpoint_list_push(scratch.arena, &msg->user_bps, &ctrl_user_bp); } diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index 6ed68067..45a3caf8 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -33,8 +33,7 @@ struct D_Breakpoint { String8 file_path; TxtPt pt; - String8 symbol_name; - U64 vaddr; + String8 vaddr_expr; String8 condition; }; diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 1bdd54e4..7e1a9599 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -4,7 +4,7 @@ //- GENERATED CODE C_LINKAGE_BEGIN -RD_VocabInfo rd_vocab_info_table[293] = +RD_VocabInfo rd_vocab_info_table[295] = { {str8_lit_comp("auto_view_rule"), str8_lit_comp("auto_view_rules"), str8_lit_comp("Auto View Rule"), str8_lit_comp("Auto View Rules"), RD_IconKind_Binoculars}, {str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, @@ -14,6 +14,8 @@ RD_VocabInfo rd_vocab_info_table[293] = {str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled}, {str8_lit_comp("condition"), str8_lit_comp("conditions"), str8_lit_comp("Condition"), str8_lit_comp("Conditions"), RD_IconKind_Null}, {str8_lit_comp("location"), str8_lit_comp("locations"), str8_lit_comp("Location"), str8_lit_comp("Locations"), RD_IconKind_Null}, +{str8_lit_comp("source_location"), str8_lit_comp("source_locations"), str8_lit_comp("Source Location"), str8_lit_comp("Source Locations"), RD_IconKind_Null}, +{str8_lit_comp("address_location"), str8_lit_comp("address_locations"), str8_lit_comp("Address Location"), str8_lit_comp("Address Locations"), RD_IconKind_Null}, {str8_lit_comp("target"), str8_lit_comp("targets"), str8_lit_comp("Target"), str8_lit_comp("Targets"), RD_IconKind_Target}, {str8_lit_comp("executable"), str8_lit_comp("executables"), str8_lit_comp("Executable"), str8_lit_comp("Executables"), RD_IconKind_Module}, {str8_lit_comp("arguments"), str8_lit_comp("arguments"), str8_lit_comp("Arguments"), str8_lit_comp("Arguments"), RD_IconKind_Null}, @@ -305,8 +307,8 @@ RD_NameSchemaInfo rd_name_schema_info_table[12] = { {str8_lit_comp("settings"), str8_lit_comp("x:\n{\n @default(1) 'hover_animations': bool,\n @default(1) 'press_animations': bool,\n @default(0) 'focus_animations': bool,\n @default(1) 'tooltip_animations': bool,\n @default(1) 'menu_animations': bool,\n @default(1) 'scrolling_animations': bool,\n @default(1) 'background_blur': bool,\n @default(1) 'thread_lines': bool,\n @default(1) 'breakpoint_lines': bool,\n @default(1) 'thread_glow': bool,\n @default(1) 'breakpoint_glow': bool,\n @default(0) 'opaque_backgrounds': bool,\n @default(1) 'smooth_main_text': bool,\n @default(0) 'smooth_code_text': bool,\n @default(1) 'hint_main_text': bool,\n @default(1) 'hint_code_text': bool,\n @default(2) 'tab_width': @range[1, 32] u64,\n @can_be_per_window 'main_font_size': @range[6, 72] u64,\n @can_be_per_window 'code_font_size': @range[1, 32] u64,\n}\n")}, {str8_lit_comp("target"), str8_lit_comp("@commands(launch_and_run, launch_and_init, select_cfg, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': path,\n 'entry_point': code_string,\n 'stdout_path': path,\n 'stderr_path': path,\n 'stdin_path': path,\n 'debug_subprocesses': bool,\n 'environment': query,\n}\n")}, -{str8_lit_comp("breakpoint"), str8_lit_comp("@commands(enable_cfg, remove_cfg)\n@collection_commands(add_breakpoint, add_address_breakpoint, add_function_breakpoint)\nx:\n{\n 'label': code_string,\n 'condition': code_string,\n 'location': location,\n 'hit_count': u64,\n 'disabled': bool,\n}\n")}, -{str8_lit_comp("watch_pin"), str8_lit_comp("@commands(remove_cfg)\n@collection_commands(add_watch_pin)\nx:\n{\n 'expression': code_string,\n 'view_rule': code_string,\n 'location': location,\n}\n")}, +{str8_lit_comp("breakpoint"), str8_lit_comp("@commands(enable_cfg, remove_cfg)\n@collection_commands(add_breakpoint, add_address_breakpoint, add_function_breakpoint)\nx:\n{\n 'label': code_string,\n 'condition': code_string,\n 'source_location': path_pt,\n 'address_location': code_string,\n 'hit_count': u64,\n 'disabled': bool,\n}\n")}, +{str8_lit_comp("watch_pin"), str8_lit_comp("@commands(remove_cfg)\n@collection_commands(add_watch_pin)\nx:\n{\n 'expression': code_string,\n 'view_rule': code_string,\n 'source_location': path_pt,\n 'address_location': code_string,\n}\n")}, {str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @commands(remove_cfg) x:{'source':path, 'dest':path}")}, {str8_lit_comp("auto_view_rule"), str8_lit_comp("@collection_commands(add_auto_view_rule) @commands(remove_cfg) x:{'type':code_string, 'view_rule':code_string}")}, {str8_lit_comp("recent_project"), str8_lit_comp("x:{'path':path}")}, @@ -528,8 +530,8 @@ RD_CmdKindInfo rd_cmd_kind_info_table[213] = { str8_lit_comp("duplicate_cfg"), str8_lit_comp("Duplicates a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("relocate_cfg"), str8_lit_comp("Relocates a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("add_breakpoint"), str8_lit_comp("Places a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_address_breakpoint"), str8_lit_comp("Places a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("Places a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp("query:procedures"), str8_lit_comp("symbol_lister"), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_address_breakpoint"), str8_lit_comp("Places a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("Places a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp("query:procedures"), str8_lit_comp("symbol_lister"), CTRL_EntityKind_Null}}, { str8_lit_comp("toggle_breakpoint"), str8_lit_comp("Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}}, { str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 0ec59375..11182c9d 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -631,7 +631,7 @@ RD_Query query; .os_event = rd_regs()->os_event,\ C_LINKAGE_BEGIN -extern RD_VocabInfo rd_vocab_info_table[293]; +extern RD_VocabInfo rd_vocab_info_table[295]; extern RD_NameSchemaInfo rd_name_schema_info_table[12]; extern Rng1U64 rd_reg_slot_range_table[40]; extern String8 rd_binding_version_remap_old_name_table[8]; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 38125746..d1365410 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -26,6 +26,8 @@ RD_VocabTable: {breakpoint _ "Breakpoint" _ CircleFilled } {condition _ "Condition" _ Null } {location _ "Location" _ Null } + {source_location _ "Source Location" _ Null } + {address_location _ "Address Location" _ Null } {target _ "Target" _ Target } {executable _ "Executable" _ Module } {arguments arguments "Arguments" "Arguments" Null } @@ -180,11 +182,12 @@ RD_VocabTable: @collection_commands(add_breakpoint, add_address_breakpoint, add_function_breakpoint) x: { - 'label': code_string, - 'condition': code_string, - 'location': location, - 'hit_count': u64, - 'disabled': bool, + 'label': code_string, + 'condition': code_string, + 'source_location': path_pt, + 'address_location': code_string, + 'hit_count': u64, + 'disabled': bool, } ```, } @@ -197,9 +200,10 @@ RD_VocabTable: @collection_commands(add_watch_pin) x: { - 'expression': code_string, - 'view_rule': code_string, - 'location': location, + 'expression': code_string, + 'view_rule': code_string, + 'source_location': path_pt, + 'address_location': code_string, } ```, } @@ -542,8 +546,8 @@ RD_CmdTable: // | | | | //- rjf: breakpoints {AddBreakpoint 1 1 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" "" } - {AddAddressBreakpoint 1 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "$breakpoints," } - {AddFunctionBreakpoint 1 0 "query:procedures" String symbol_lister Nil Null 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address(es) of the specified function." "" "$breakpoints," } + {AddAddressBreakpoint 1 0 "" Expr null Nil Null 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "$breakpoints," } + {AddFunctionBreakpoint 1 0 "query:procedures" Expr symbol_lister Nil Null 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address(es) of the specified function." "" "$breakpoints," } {ToggleBreakpoint 1 1 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" "$text_pt," } {EnableBreakpoint 1 1 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 0 0 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" "" } {DisableBreakpoint 1 1 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 0 0 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" "" } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index c5a89a2f..235c58fc 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1627,12 +1627,12 @@ rd_cfg_tree_list_from_string(Arena *arena, String8 string) rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n); } rec = md_node_rec_depth_first_pre(src_n, tln); + if(dst_active_parent_n == &rd_nil_cfg) + { + dst_root_n = dst_n; + } if(rec.push_count > 0) { - if(dst_active_parent_n == &rd_nil_cfg) - { - dst_root_n = dst_n; - } dst_active_parent_n = dst_n; } else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) @@ -2094,8 +2094,9 @@ rd_location_from_cfg(RD_Cfg *cfg) { RD_Location dst_loc = {0}; { - RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("location")); - if(src_loc->first != &rd_nil_cfg && src_loc->first->first != &rd_nil_cfg) + RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); + RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); + if(src_loc != &rd_nil_cfg) { dst_loc.file_path = src_loc->first->string; try_s64_from_str8_c_rules(src_loc->first->first->string, &dst_loc.pt.line); @@ -2104,19 +2105,9 @@ rd_location_from_cfg(RD_Cfg *cfg) dst_loc.pt.column = 1; } } - else + else if(addr_loc != &rd_nil_cfg) { - Temp scratch = scratch_begin(0, 0); - MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_loc->first->string); - if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|MD_TokenFlag_StringLiteral)) - { - dst_loc.name = src_loc->first->string; - } - else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) - { - try_u64_from_str8_c_rules(src_loc->first->string, &dst_loc.vaddr); - } - scratch_end(scratch); + dst_loc.expr = addr_loc->first->string; } } return dst_loc; @@ -2547,7 +2538,7 @@ rd_eval_blob_from_cfg(Arena *arena, RD_Cfg *cfg) MD_Node *member_schema = md_child_from_string(schema, child_name, 0); String8 member_type_name = member_schema->first->string; RD_Cfg *child = rd_cfg_child_from_string(cfg, child_name); - if(str8_match(member_type_name, str8_lit("location"), 0)) + if(str8_match(member_type_name, str8_lit("path_pt"), 0)) { U64 off = type->byte_size + variable_width_parts.total_size; str8_list_push(scratch.arena, &fixed_width_parts, push_str8_copy(scratch.arena, str8_struct(&off))); @@ -5292,11 +5283,17 @@ rd_view_ui(Rng2F32 rect) } // rjf: can edit? -> begin editing - else if(cell_info.flags & RD_WatchCellFlag_CanEdit) + else if(!(sig.f & UI_SignalFlag_KeyboardPressed) && cell_info.flags & RD_WatchCellFlag_CanEdit) { rd_cmd(RD_CmdKind_Edit); } + // rjf: can expand? -> expand + else if(sig.f & UI_SignalFlag_KeyboardPressed && row_is_expandable) + { + next_row_expanded = !row_expanded; + } + // rjf: can't edit, but has address info? -> go to address else if(cell_info.eval.space.kind == RD_EvalSpaceKind_CtrlEntity) { @@ -11838,6 +11835,10 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 string) rd_regs()->cursor = pair.pt; } }break; + case RD_RegSlot_Expr: + { + rd_regs()->expr = push_str8_copy(rd_frame_arena(), string); + }break; case RD_RegSlot_Cursor: { U64 v = 0; @@ -13048,7 +13049,7 @@ rd_frame(void) E_TypeKey code_string_type_key = {0}; E_TypeKey path_type_key = {0}; E_TypeKey string_type_key = {0}; - E_TypeKey location_type_key = {0}; + E_TypeKey path_pt_type_key = {0}; { E_MemberList vaddr_range_members_list = {0}; e_member_list_push_new(scratch.arena, &vaddr_range_members_list, .type_key = e_type_key_basic(E_TypeKind_U64), .name = str8_lit("min"), .off = 0); @@ -13060,7 +13061,7 @@ rd_frame(void) code_string_type_key = e_type_key_cons_ptr(arch_from_context(), e_type_key_basic(E_TypeKind_U8), 1, E_TypeFlag_IsCodeText); path_type_key = e_type_key_cons_ptr(arch_from_context(), e_type_key_basic(E_TypeKind_U8), 1, E_TypeFlag_IsPathText); string_type_key = e_type_key_cons_ptr(arch_from_context(), e_type_key_basic(E_TypeKind_U8), 1, E_TypeFlag_IsPlainText); - location_type_key = e_type_key_cons_ptr(arch_from_context(), e_type_key_basic(E_TypeKind_U8), 1, E_TypeFlag_IsPlainText|E_TypeFlag_IsCodeText|E_TypeFlag_IsPathText); + path_pt_type_key = e_type_key_cons_ptr(arch_from_context(), e_type_key_basic(E_TypeKind_U8), 1, E_TypeFlag_IsPathText); } //- rjf: build types for each evallable meta name @@ -13077,7 +13078,7 @@ rd_frame(void) { str8_lit("code_string"), code_string_type_key }, { str8_lit("path"), path_type_key }, { str8_lit("string"), string_type_key }, - { str8_lit("location"), location_type_key }, + { str8_lit("path_pt"), path_pt_type_key }, }; E_TypeKey evallable_meta_types[ArrayCount(evallable_meta_names)] = {0}; for EachElement(idx, evallable_meta_names) @@ -15822,25 +15823,38 @@ Z(getting_started) case RD_CmdKind_RelocateCfg: { RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); - RD_Cfg *loc = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("location")); - for(RD_Cfg *child = loc->first, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) + + // rjf: release old location info { - next = child->next; - rd_cfg_release(child); + RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); + RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); + rd_cfg_release(src_loc); + rd_cfg_release(addr_loc); } - if(rd_regs()->cursor.line != 0) + + // rjf: attach new location info { - RD_Cfg *file = rd_cfg_new(loc, rd_regs()->file_path); - RD_Cfg *line = rd_cfg_newf(file, "%I64d", rd_regs()->cursor.line); - rd_cfg_newf(line, "%I64d", rd_regs()->cursor.column); - } - else if(rd_regs()->vaddr != 0) - { - rd_cfg_newf(loc, "0x%I64x", rd_regs()->vaddr); - } - else if(rd_regs()->string.size != 0) - { - rd_cfg_new(loc, rd_regs()->string); + String8 file_path = rd_regs()->file_path; + TxtPt pt = rd_regs()->cursor; + String8 expr_string = rd_regs()->expr; + U64 vaddr = rd_regs()->vaddr; + if(expr_string.size == 0 && vaddr != 0) + { + expr_string = push_str8f(scratch.arena, "0x%I64x", vaddr); + } + if(file_path.size != 0 && pt.line != 0) + { + RD_Cfg *src_loc = rd_cfg_new(cfg, str8_lit("source_location")); + RD_Cfg *file = rd_cfg_new(src_loc, file_path); + RD_Cfg *line = rd_cfg_newf(file, "%I64d", pt.line); + RD_Cfg *col = rd_cfg_newf(line, "%I64d", pt.column); + (void)col; + } + else if(expr_string.size != 0) + { + RD_Cfg *vaddr_loc = rd_cfg_new(cfg, str8_lit("address_location")); + rd_cfg_new(vaddr_loc, expr_string); + } } }break; @@ -15850,9 +15864,13 @@ Z(getting_started) { String8 file_path = rd_regs()->file_path; TxtPt pt = rd_regs()->cursor; - String8 string = rd_regs()->string; U64 vaddr = rd_regs()->vaddr; - if(file_path.size != 0 || string.size != 0 || vaddr != 0) + String8 expr = rd_regs()->expr; + if(expr.size == 0 && vaddr != 0) + { + expr = push_str8f(scratch.arena, "0x%I64x", vaddr); + } + if(file_path.size != 0 || expr.size != 0) { B32 removed_already_existing = 0; if(kind == RD_CmdKind_ToggleBreakpoint) @@ -15861,13 +15879,10 @@ Z(getting_started) for(RD_CfgNode *n = bps.first; n != 0; n = n->next) { RD_Cfg *bp = n->v; - RD_Cfg *loc = rd_cfg_child_from_string(bp, str8_lit("location")); - S64 loc_line = 0; - U64 loc_vaddr = 0; - B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); - B32 loc_matches_string = (string.size != 0 && str8_match(loc->first->string, string, 0)); - B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); - if(loc_matches_file_pt || loc_matches_string || loc_matches_vaddr) + RD_Location loc = rd_location_from_cfg(bp); + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); + B32 loc_matches_expr = (expr.size != 0 && str8_match(expr, loc.expr, 0)); + if(loc_matches_file_pt || loc_matches_expr) { rd_cfg_release(bp); removed_already_existing = 1; @@ -15879,30 +15894,14 @@ Z(getting_started) { RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint")); - RD_Cfg *loc = rd_cfg_new(bp, str8_lit("location")); - if(vaddr != 0) - { - rd_cfg_newf(loc, "0x%I64x", vaddr); - } - else if(string.size != 0) - { - rd_cfg_new(loc, string); - } - else if(file_path.size != 0) - { - RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); - rd_cfg_newf(file_path_cfg, "%I64d", pt.line); - } + rd_cmd(RD_CmdKind_RelocateCfg, .cfg = bp->id); } } }break; case RD_CmdKind_AddAddressBreakpoint: - { - rd_cmd(RD_CmdKind_AddBreakpoint, .string = str8_zero()); - }break; case RD_CmdKind_AddFunctionBreakpoint: { - rd_cmd(RD_CmdKind_AddBreakpoint, .vaddr = 0); + rd_cmd(RD_CmdKind_AddBreakpoint); }break; //- rjf: watch pins @@ -15922,17 +15921,13 @@ Z(getting_started) { RD_Cfg *wp = n->v; RD_Cfg *expr = rd_cfg_child_from_string(wp, str8_lit("expression")); - RD_Cfg *loc = rd_cfg_child_from_string(wp, str8_lit("location")); - S64 loc_line = 0; - U64 loc_vaddr = 0; - B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); - B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); - B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr->first->string, expr_string, 0)); - if(loc_matches_expr && (loc_matches_file_pt || loc_matches_vaddr)) + RD_Location loc = rd_location_from_cfg(wp); + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); + B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr_string, loc.expr, 0)); + if((loc_matches_file_pt || loc_matches_expr) && str8_match(expr->first->string, expr_string, 0)) { rd_cfg_release(wp); removed_already_existing = 1; - break; } } } @@ -15942,18 +15937,9 @@ Z(getting_started) RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin")); RD_Cfg *expr = rd_cfg_new(wp, str8_lit("expression")); RD_Cfg *view_rule = rd_cfg_new(wp, str8_lit("view_rule")); - RD_Cfg *loc = rd_cfg_new(wp, str8_lit("location")); rd_cfg_new(expr, expr_string); rd_cfg_new(view_rule, view_rule_string); - if(vaddr != 0) - { - rd_cfg_newf(loc, "0x%I64x", vaddr); - } - else if(file_path.size != 0) - { - RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); - rd_cfg_newf(file_path_cfg, "%I64d", pt.line); - } + rd_cmd(RD_CmdKind_RelocateCfg, .cfg = wp->id); } }break; @@ -16790,8 +16776,7 @@ Z(getting_started) D_Breakpoint *dst_bp = &breakpoints.v[idx]; dst_bp->file_path = src_bp_loc.file_path; dst_bp->pt = src_bp_loc.pt; - dst_bp->symbol_name = src_bp_loc.name; - dst_bp->vaddr = src_bp_loc.vaddr; + dst_bp->vaddr_expr = src_bp_loc.expr; dst_bp->condition = non_ctrl_thread_static_condition; idx += 1; } @@ -16937,6 +16922,7 @@ Z(getting_started) try_u64_from_str8_c_rules(hit_count_root->first->string, &hit_count); RD_Location loc = rd_location_from_cfg(bp); D_LineList loc_lines = d_lines_from_file_path_line_num(scratch.arena, loc.file_path, loc.pt.line); + E_Value loc_value = e_value_from_string(loc.expr); if(loc_lines.first != 0) { for(D_LineNode *n = loc_lines.first; n != 0; n = n->next) @@ -16948,18 +16934,10 @@ Z(getting_started) } } } - else if(loc.vaddr != 0 && vaddr == loc.vaddr) + else if(loc_value.u64 != 0 && vaddr == loc_value.u64) { hit_count += 1; } - else if(loc.name.size != 0) - { - U64 symb_voff = d_voff_from_dbgi_key_symbol_name(&dbgi_key, loc.name); - if(symb_voff == voff) - { - hit_count += 1; - } - } rd_cfg_new_replacef(hit_count_root, "%I64u", hit_count); } } diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 644cd104..f87ff098 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -339,8 +339,7 @@ struct RD_Location { String8 file_path; TxtPt pt; - U64 vaddr; - String8 name; + String8 expr; }; //////////////////////////////// diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index e14a5b0a..41ecf5e0 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -319,9 +319,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { RD_Cfg *bp = n->v; RD_Location loc = rd_location_from_cfg(bp); - if(contains_1u64(dasm_vaddr_range, loc.vaddr)) + E_Value loc_value = e_value_from_string(loc.expr); + if(contains_1u64(dasm_vaddr_range, loc_value.u64)) { - U64 off = loc.vaddr - dasm_vaddr_range.min; + U64 off = loc_value.u64 - dasm_vaddr_range.min; U64 idx = dasm_line_array_idx_from_code_off__linear_scan(dasm_lines, off); S64 line_num = (S64)idx+1; if(contains_1s64(visible_line_num_range, line_num)) @@ -341,9 +342,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { RD_Cfg *wp = n->v; RD_Location loc = rd_location_from_cfg(wp); - if(contains_1u64(dasm_vaddr_range, loc.vaddr)) + E_Value loc_value = e_value_from_string(loc.expr); + if(contains_1u64(dasm_vaddr_range, loc_value.u64)) { - U64 off = loc.vaddr - dasm_vaddr_range.min; + U64 off = loc_value.u64 - dasm_vaddr_range.min; U64 idx = dasm_line_array_idx_from_code_off__linear_scan(dasm_lines, off); S64 line_num = (S64)idx+1; if(contains_1s64(visible_line_num_range, line_num)) diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 3ccc4d96..7d2b0217 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -250,6 +250,18 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg) start_secondary(); } + //- rjf: push address location + if(loc.expr.size != 0) + { + RD_Font(RD_FontSlot_Code) + { + DR_FStrList fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, params.color, loc.expr); + dr_fstrs_concat_in_place(&result, &fstrs); + } + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + //- rjf: push target executable name if(target.exe.size != 0) { @@ -291,7 +303,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg) { String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string; U64 hit_count = 0; - if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count)) + if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count) && hit_count != 0) { String8 hit_count_text = push_str8f(arena, "(%I64u hit%s)", hit_count, hit_count == 1 ? "" : "s"); dr_fstrs_push_new(arena, &result, ¶ms, hit_count_text);