diff --git a/build.bat b/build.bat index d17d25f3..10a505a3 100644 --- a/build.bat +++ b/build.bat @@ -47,7 +47,7 @@ set cl_debug= call cl /Od /D_DEBUG %cl_common% set cl_release= call cl /O2 /DNDEBUG %cl_common% set clang_debug= call clang -g -O0 -D_DEBUG %clang_common% set clang_release= call clang -g -O3 -DNDEBUG %clang_common% -set cl_link= /link /natvis:"%~dp0\src\natvis\base.natvis" +set cl_link= /link /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" set clang_link= -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" set cl_out= /out: set clang_out= -o diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index bd70ea65..2221a0f5 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -2869,23 +2869,6 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) { trap_addr = point->jump_dest_vaddr; flags &= ~CTRL_TrapFlag_SingleStepAfterHit; - - // rjf: read instruction one layer deep after a jump and determine if - // it is just jumping to an unconditional jump (e.g. a function - // dispatch table) - if so, then just follow one more layer - String8 dst_machine_code = {0}; - dst_machine_code.str = push_array_no_zero(scratch.arena, U8, max_instruction_size_from_arch(arch)); - dst_machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(trap_addr, trap_addr+max_instruction_size_from_arch(arch)), dst_machine_code.str); - if(dst_machine_code.size != 0) - { - DF_Inst inst = df_single_inst_from_machine_code(scratch.arena, arch, 0, dst_machine_code); - if((inst.flags & DF_InstFlag_UnconditionalJump || - inst.flags & DF_InstFlag_Call) && - inst.rel_voff != 0) - { - trap_addr = (U64)(trap_addr + (S64)((S32)inst.rel_voff)); - } - } } } @@ -3649,6 +3632,7 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) df_state->unwind_cache_invalidated = 1; df_state->locals_cache_invalidated = 1; df_state->member_cache_invalidated = 1; + df_state->local_dynamic_type_override_cache_invalidated = 1; } // rjf: early mutation of unwind cache for immediate frontend effect @@ -3914,6 +3898,7 @@ df_eval_parse_ctx_from_module_voff(DBGI_Scope *scope, DF_Entity *module, U64 vof EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, voff); EVAL_String2NumMap *member_map = df_query_cached_member_map_from_binary_voff(binary, voff); + EVAL_String2NumMap *local_dynamic_type_override_map = df_query_cached_local_dynamic_type_override_map_from_module_voff(module, voff); //- rjf: build ctx EVAL_ParseCtx ctx = zero_struct; @@ -3926,6 +3911,7 @@ df_eval_parse_ctx_from_module_voff(DBGI_Scope *scope, DF_Entity *module, U64 vof ctx.reg_alias_map = reg_alias_map; ctx.locals_map = locals_map; ctx.member_map = member_map; + ctx.local_dynamic_type_override_map = local_dynamic_type_override_map; } scratch_end(scratch); return ctx; @@ -4038,6 +4024,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) ctx.reg_alias_map = &eval_string2num_map_nil; ctx.locals_map = &eval_string2num_map_nil; ctx.member_map = &eval_string2num_map_nil; + ctx.local_dynamic_type_override_map = &eval_string2num_map_nil; } scratch_end(scratch); @@ -4225,6 +4212,49 @@ internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg) { ProfBeginFunction(); + +#if 0 + //- rjf: pointer-to-struct -> read result & find "derived class" for "real" + // type of evaluation + { + TG_Kind kind = tg_kind_from_key(eval.type_key); + if(kind == TG_Kind_Ptr) + { + TG_Key direct_key = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, eval.type_key); + TG_Kind direct_kind = tg_kind_from_key(direct_key); + if((direct_kind == TG_Kind_Struct || direct_kind == TG_Kind_Class) && parse_ctx->rdbg->global_vmap != 0) + { + DF_Eval ptr_addr_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + U64 vaddr = ptr_addr_eval.imm_u64; + String8 ptr_val_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, r1u64(vaddr, vaddr+bit_size_from_arch(parse_ctx->arch)/8)); + if(ptr_val_memory.size >= bit_size_from_arch(parse_ctx->arch)/8) + { + U64 vtable_ptr_maybe = 0; + MemoryCopy(&vtable_ptr_maybe, ptr_val_memory.str, bit_size_from_arch(parse_ctx->arch)/8); + U64 voff = df_voff_from_vaddr(module, vtable_ptr_maybe); + U64 global_idx = raddbg_vmap_idx_from_voff(parse_ctx->rdbg->global_vmap, parse_ctx->rdbg->global_vmap_count, voff); + if(0 < global_idx && global_idx < parse_ctx->rdbg->global_variable_count) + { + RADDBG_GlobalVariable *global_var = &parse_ctx->rdbg->global_variables[global_idx]; + if(global_var->link_flags & RADDBG_LinkFlag_TypeScoped && + 0 < global_var->container_idx && global_var->container_idx < parse_ctx->rdbg->udt_count) + { + RADDBG_UDT *udt = &parse_ctx->rdbg->udts[global_var->container_idx]; + if(0 < udt->self_type_idx && udt->self_type_idx < parse_ctx->rdbg->type_node_count) + { + RADDBG_TypeNode *type = &parse_ctx->rdbg->type_nodes[udt->self_type_idx]; + TG_Key derived_type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type->kind), (U64)udt->self_type_idx); + eval.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, derived_type_key, 0); + } + } + } + } + } + } + } +#endif + + //- rjf: apply view rules for(DF_CfgVal *val = cfg->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) { DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); @@ -6035,6 +6065,56 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) return map; } +internal EVAL_String2NumMap * +df_query_cached_local_dynamic_type_override_map_from_module_voff(DF_Entity *module, U64 voff) +{ + ProfBeginFunction(); + EVAL_String2NumMap *map = &eval_string2num_map_nil; + { + DF_RunLocalsCache *cache = &df_state->local_dynamic_type_override_cache; + if(cache->table_size == 0) + { + cache->table_size = 256; + cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); + } + DF_Handle handle = df_handle_from_entity(module); + U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 slot_idx = hash % cache->table_size; + DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; + DF_RunLocalsCacheNode *node = 0; + for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) + { + if(df_handle_match(n->binary, handle) && n->voff == voff) + { + node = n; + break; + } + } + if(node == 0) + { + DBGI_Scope *scope = dbgi_scope_open(); +#if 0 + EVAL_String2NumMap *map = df_push_member_map_from_binary_voff(cache->arena, scope, binary, voff); + if(map->slots_count != 0) + { + node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); + node->binary = handle; + node->voff = voff; + node->locals_map = map; + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + } +#endif + dbgi_scope_close(scope); + } + if(node != 0) + { + map = node->locals_map; + } + } + ProfEnd(); + return map; +} + //- rjf: top-level command dispatch internal void @@ -6099,6 +6179,7 @@ df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist df_state->unwind_cache.arena = arena_alloc(); df_state->locals_cache.arena = arena_alloc(); df_state->member_cache.arena = arena_alloc(); + df_state->local_dynamic_type_override_cache.arena = arena_alloc(); // rjf: set up eval view cache df_state->eval_view_cache.slots_count = 4096; @@ -6502,6 +6583,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_state->unwind_cache_invalidated = 1; df_state->locals_cache_invalidated = 1; df_state->member_cache_invalidated = 1; + df_state->local_dynamic_type_override_cache_invalidated = 1; } //- rjf: refresh unwind cache @@ -6553,6 +6635,16 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) cache->table = 0; } + //- rjf: clear local -> dynamic type override cache + if(df_state->local_dynamic_type_override_cache_invalidated && !df_ctrl_targets_running()) + { + df_state->local_dynamic_type_override_cache_invalidated = 0; + DF_RunLocalsCache *cache = &df_state->local_dynamic_type_override_cache; + arena_clear(cache->arena); + cache->table_size = 0; + cache->table = 0; + } + scratch_end(scratch); } diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index a3bdc65a..3a0f15d8 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -1135,6 +1135,8 @@ struct DF_State DF_RunLocalsCache locals_cache; B32 member_cache_invalidated; DF_RunLocalsCache member_cache; + B32 local_dynamic_type_override_cache_invalidated; + DF_RunLocalsCache local_dynamic_type_override_cache; // rjf: eval view cache DF_EvalViewCache eval_view_cache; @@ -1655,6 +1657,7 @@ internal U64 df_query_cached_rip_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal EVAL_String2NumMap *df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff); internal EVAL_String2NumMap *df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_query_cached_local_dynamic_type_override_map_from_module_voff(DF_Entity *module, U64 voff); //- rjf: top-level command dispatch internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); diff --git a/src/eval/eval_parser.c b/src/eval/eval_parser.c index 58e80acf..e1be7f3c 100644 --- a/src/eval/eval_parser.c +++ b/src/eval/eval_parser.c @@ -778,6 +778,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 case EVAL_TokenKind_Identifier: { B32 mapped_identifier = 0; + B32 identifier_type_is_possibly_dynamically_overridden = 0; B32 identifier_looks_like_type_expr = 0; RADDBG_LocationKind loc_kind = RADDBG_LocationKind_NULL; RADDBG_LocationRegister loc_reg = {0}; @@ -808,6 +809,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 ctx->rdbg->type_nodes != 0) { mapped_identifier = 1; + identifier_type_is_possibly_dynamically_overridden = 1; RADDBG_Local *local_var = &ctx->rdbg->locals[local_num-1]; // rjf: grab location info @@ -978,6 +980,20 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 } } + //- rjf: identifier refers to type which may be possibly overridden -> look up into + // identifier -> dynamic type table & patch + if(identifier_type_is_possibly_dynamically_overridden) + { + U64 base_type_num = eval_num_from_string(ctx->local_dynamic_type_override_map, token_string); + if(base_type_num != 0) + { + U64 type_idx = base_type_num; + RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; + TG_Key base_type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), type_idx); + type_key = tg_cons_type_make(ctx->type_graph, TG_Kind_Ptr, base_type_key, 0); + } + } + //- rjf: attach on map if(mapped_identifier != 0) { diff --git a/src/eval/eval_parser.h b/src/eval/eval_parser.h index 759304f5..ac981408 100644 --- a/src/eval/eval_parser.h +++ b/src/eval/eval_parser.h @@ -98,6 +98,7 @@ struct EVAL_ParseCtx EVAL_String2NumMap *reg_alias_map; EVAL_String2NumMap *locals_map; EVAL_String2NumMap *member_map; + EVAL_String2NumMap *local_dynamic_type_override_map; }; ////////////////////////////////