From 17582920749bde9466482ca2d57a807d78b3e42d Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 9 Oct 2024 15:07:54 -0700 Subject: [PATCH] pipe breakpoint-condition-touched meta-evaluations to control thread; allow evaluation of meta-evaluations in conditional breakpoints --- src/ctrl/ctrl_core.c | 72 +++++++++++++++++++++++++++---- src/ctrl/ctrl_core.h | 2 +- src/raddbg/raddbg_core.c | 91 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 11 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index dafd1426..392f8a2d 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -1260,6 +1260,7 @@ ctrl_init(void) ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); ctrl_state->dmn_event_arena = arena_alloc(); ctrl_state->user_entry_point_arena = arena_alloc(); + ctrl_state->user_meta_eval_arena = arena_alloc(); for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) { if(ctrl_exception_code_kind_default_enable_table[k]) @@ -3190,7 +3191,15 @@ ctrl_thread__entry_point(void *p) { log_infof("user2ctrl_msg:{kind:\"%S\"}\n", ctrl_string_from_msg_kind(msg->kind)); } - MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + + //- rjf: unpack per-message parameterizations & store + { + MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); + arena_clear(ctrl_state->user_meta_eval_arena); + ctrl_state->user_meta_evals = *deep_copy_from_struct(ctrl_state->user_meta_eval_arena, CTRL_MetaEvalArray, &msg->meta_evals); + } + + //- rjf: process message switch(msg->kind) { case CTRL_MsgKind_Null: @@ -4104,6 +4113,8 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) switch(space.kind) { default:{}break; + + //- rjf: intra-entity reads (process memory or thread registers) case CTRL_EvalSpaceKind_Entity: { CTRL_Entity *entity = (CTRL_Entity *)space.u64_0; @@ -4129,6 +4140,42 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) }break; } }break; + + //- rjf: meta evaluations + case CTRL_EvalSpaceKind_Meta: + { + Temp scratch = scratch_begin(0, 0); + U64 meta_eval_idx = space.u64s[0]; + if(meta_eval_idx < ctrl_state->user_meta_evals.count) + { + CTRL_MetaEval *meval = &ctrl_state->user_meta_evals.v[meta_eval_idx]; + + // rjf: copy meta evaluation to scratch arena, to form range of legal reads + arena_push(scratch.arena, 0, 64); + String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); + U64 pos_min = arena_pos(scratch.arena); + CTRL_MetaEval *meval_read = struct_from_serialized(scratch.arena, CTRL_MetaEval, meval_srlzed); + U64 pos_opl = arena_pos(scratch.arena); + + // rjf: rebase all pointer values in meta evaluation to be relative to base pointer + struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); + + // rjf: perform actual read + Rng1U64 legal_range = r1u64(0, pos_opl-pos_min); + if(contains_1u64(legal_range, range.min)) + { + result = 1; + U64 range_dim = dim_1u64(range); + U64 bytes_to_read = Min(range_dim, (legal_range.max - range.min)); + MemoryCopy(out, ((U8 *)meval_read) + range.min, bytes_to_read); + if(bytes_to_read < range_dim) + { + MemoryZero((U8 *)out + bytes_to_read, range_dim - bytes_to_read); + } + } + } + scratch_end(scratch); + }break; } return result; } @@ -5031,6 +5078,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) 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; @@ -5049,13 +5097,26 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) 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; { - // TODO(rjf): pipe this here from frontend - ir_ctx.macro_map = &e_string2expr_map_nil; + 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_TypeKey meval_type_key = e_type_key_cons_base(type(CTRL_MetaEval)); + for EachIndex(idx, ctrl_state->user_meta_evals.count) + { + E_Space space = e_space_make(CTRL_EvalSpaceKind_Meta); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = meval_type_key; + e_string2expr_map_insert(temp.arena, ctx->macro_map, ctrl_state->user_meta_evals.v[idx].label, expr); + } } + e_select_ir_ctx(&ir_ctx); // rjf: build eval interpretation context E_InterpretCtx interpret_ctx = zero_struct; @@ -5071,11 +5132,6 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctx->module_base[0]= module->vaddr_range.min; ctx->tls_base = push_array(temp.arena, U64, 1); } - - // rjf: equip contexts - e_select_type_ctx(&type_ctx); - e_select_parse_ctx(&parse_ctx); - e_select_ir_ctx(&ir_ctx); e_select_interpret_ctx(&interpret_ctx); // rjf: evaluate diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 8dde24f6..6892744e 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -817,7 +817,7 @@ struct CTRL_State Arena *user_entry_point_arena; String8List user_entry_points; Arena *user_meta_eval_arena; - CTRL_MetaEvalArray *user_meta_evals; + CTRL_MetaEvalArray user_meta_evals; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; U64 process_counter; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 7258766b..d939bbfe 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -15393,6 +15393,7 @@ rd_frame(void) //- rjf: gather targets // D_TargetArray targets = {0}; + ProfScope("gather targets") { RD_EntityList target_entities = rd_query_cached_entity_list_with_kind(RD_EntityKind_Target); targets.count = target_entities.count; @@ -15415,6 +15416,7 @@ rd_frame(void) //- rjf: gather breakpoints // D_BreakpointArray breakpoints = {0}; + ProfScope("gather breakpoints") { RD_EntityList bp_entities = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); breakpoints.count = bp_entities.count; @@ -15457,11 +15459,96 @@ rd_frame(void) } //////////////////////////// - //- rjf: gather meta evaluations + //- rjf: gather needed meta evaluations // CTRL_MetaEvalArray meta_evals = {0}; + ProfScope("gather needed meta evaluations") { - // TODO(rjf): @msgs + typedef struct MetaEvalNode MetaEvalNode; + struct MetaEvalNode + { + MetaEvalNode *next; + CTRL_MetaEval *meval; + }; + + //- rjf: walk all breakpoints, gather touched meta-evals + U64 meval_count = 0; + MetaEvalNode *first_meval = 0; + MetaEvalNode *last_meval = 0; + for EachIndex(idx, breakpoints.count) + { + if(breakpoints.v[idx].condition.size != 0) + { + //- rjf: walk conditional breakpoint expression tree - for each leaf identifier, + // determine if it resolves to a meta-evaluation. if it does, compute the meta + // evaluation data & store + typedef struct ExprWalkTask ExprWalkTask; + struct ExprWalkTask + { + ExprWalkTask *next; + E_Expr *expr; + }; + E_Expr *expr = e_parse_expr_from_text(scratch.arena, breakpoints.v[idx].condition); + ExprWalkTask start_task = {0, expr}; + ExprWalkTask *first_task = &start_task; + for(ExprWalkTask *t = first_task; t != 0; t = t->next) + { + if(t->expr->kind == E_ExprKind_LeafIdent) + { + E_Expr *macro_expr = e_string2expr_lookup(e_ir_ctx->macro_map, t->expr->string); + if(macro_expr != &e_expr_nil) + { + E_Eval eval = e_eval_from_expr(scratch.arena, macro_expr); + switch(eval.space.kind) + { + default:{}break; + case RD_EvalSpaceKind_MetaEntity: + { + RD_Entity *entity = rd_entity_from_eval_space(eval.space); + if(!rd_entity_is_nil(entity)) + { + MetaEvalNode *meval_node = push_array(scratch.arena, MetaEvalNode, 1); + meval_node->meval = rd_ctrl_meta_eval_from_entity(scratch.arena, entity); + SLLQueuePush(first_meval, last_meval, meval_node); + meval_count += 1; + } + }break; + case RD_EvalSpaceKind_MetaCtrlEntity: + { + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); + if(entity != &ctrl_entity_nil) + { + MetaEvalNode *meval_node = push_array(scratch.arena, MetaEvalNode, 1); + meval_node->meval = rd_ctrl_meta_eval_from_ctrl_entity(scratch.arena, entity); + SLLQueuePush(first_meval, last_meval, meval_node); + meval_count += 1; + } + }break; + } + } + } + for(E_Expr *child = t->expr->first; child != &e_expr_nil; child = child->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + task->expr = child; + task->next = t->next; + t->next = task; + } + } + } + } + + //- rjf: list -> array + meta_evals.count = meval_count; + meta_evals.v = push_array(scratch.arena, CTRL_MetaEval, meta_evals.count); + { + U64 idx = 0; + for(MetaEvalNode *n = first_meval; n != 0; n = n->next) + { + MemoryCopyStruct(&meta_evals.v[idx], n->meval); + idx += 1; + } + } } ////////////////////////////