From fbd78525d2bf72e0cad8cbfce2a0bbb80a4f4ff4 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 8 Apr 2025 11:14:58 -0700 Subject: [PATCH] sketch out new eval type-system-defined hooks for all eval-layer view rules; accesses (., [] operators), expansion ranges, id <-> num mapping --- src/eval/eval_core.h | 86 +++++++++---- src/eval/eval_ir.c | 263 ++++++++++++++++++++++++++++++++++++-- src/eval/eval_types.c | 21 +-- src/eval/eval_types.h | 5 + src/raddbg/raddbg_views.c | 2 +- 5 files changed, 332 insertions(+), 45 deletions(-) diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index c34d7992..90d45c52 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -248,6 +248,30 @@ struct E_ExprList U64 count; }; +//////////////////////////////// +//~ rjf: IR Tree Types + +typedef struct E_IRNode E_IRNode; +struct E_IRNode +{ + E_IRNode *first; + E_IRNode *last; + E_IRNode *next; + RDI_EvalOp op; + E_Space space; + String8 string; + E_Value value; +}; + +typedef struct E_IRTreeAndType E_IRTreeAndType; +struct E_IRTreeAndType +{ + E_IRNode *root; + E_TypeKey type_key; + E_Mode mode; + E_MsgList msgs; +}; + //////////////////////////////// //~ rjf: Full Extracted Type Information Types @@ -326,6 +350,38 @@ struct E_EnumValArray U64 count; }; +typedef struct E_TypeExpandInfo E_TypeExpandInfo; +struct E_TypeExpandInfo +{ + void *user_data; + U64 expr_count; +}; + +#define E_TYPE_ACCESS_FUNCTION_SIG(name) E_IRTreeAndType name(Arena *arena, E_Expr *expr, E_IRTreeAndType *lhs_irtree) +#define E_TYPE_ACCESS_FUNCTION_NAME(name) e_type_access__##name +#define E_TYPE_ACCESS_FUNCTION_DEF(name) internal E_TYPE_ACCESS_FUNCTION_SIG(E_TYPE_ACCESS_FUNCTION_NAME(name)) +typedef E_TYPE_ACCESS_FUNCTION_SIG(E_TypeAccessFunctionType); + +#define E_TYPE_EXPAND_INFO_FUNCTION_SIG(name) E_TypeExpandInfo name(Arena *arena, E_IRTreeAndType *irtree, String8 filter) +#define E_TYPE_EXPAND_INFO_FUNCTION_NAME(name) e_type_expand_info__##name +#define E_TYPE_EXPAND_INFO_FUNCTION_DEF(name) internal E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TYPE_EXPAND_INFO_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TypeExpandInfoFunctionType); + +#define E_TYPE_EXPAND_RANGE_FUNCTION_SIG(name) void name(Arena *arena, void *user_data, E_Expr *expr, String8 filter, Rng1U64 idx_range, E_Expr **exprs_out, String8 *exprs_strings_out) +#define E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name) e_type_expand_range__##name +#define E_TYPE_EXPAND_RANGE_FUNCTION_DEF(name) internal E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TypeExpandRangeFunctionType); + +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(name) U64 name(void *user_data, U64 num) +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name) e_type_expand_id_from_num__##name +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(name) internal E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TypeExpandIDFromNumFunctionType); + +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(name) U64 name(void *user_data, U64 id) +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name) e_type_expand_num_from_id__##name +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(name) internal E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TypeExpandNumFromIDFunctionType); + typedef struct E_Type E_Type; struct E_Type { @@ -343,6 +399,11 @@ struct E_Type E_Member *members; E_EnumVal *enum_vals; E_Expr **args; + E_TypeAccessFunctionType *access; + E_TypeExpandInfoFunctionType *expand_info; + E_TypeExpandRangeFunctionType *expand_range; + E_TypeExpandIDFromNumFunctionType *expand_id_from_num; + E_TypeExpandNumFromIDFunctionType *expand_num_from_id; }; //////////////////////////////// @@ -357,31 +418,6 @@ struct E_Module E_Space space; }; -//////////////////////////////// -//~ rjf: IR Tree Types - -typedef struct E_IRNode E_IRNode; -struct E_IRNode -{ - E_IRNode *first; - E_IRNode *last; - E_IRNode *next; - RDI_EvalOp op; - E_Space space; - String8 string; - E_Value value; -}; - -typedef struct E_IRTreeAndType E_IRTreeAndType; -struct E_IRTreeAndType -{ - E_IRNode *root; - E_TypeKey type_key; - E_Member member; - E_Mode mode; - E_MsgList msgs; -}; - //////////////////////////////// //~ rjf: String -> Num diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index a5427b61..8d67064b 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -717,7 +717,6 @@ E_LOOKUP_ACCESS_FUNCTION_DEF(default) // rjf: fill result.irtree_and_type.root = new_tree; result.irtree_and_type.type_key = r_type; - result.irtree_and_type.member = member; result.irtree_and_type.mode = mode; } }break; @@ -1195,7 +1194,7 @@ E_IRGEN_FUNCTION_DEF(bswap) E_IRTreeAndType irtree = e_irtree_and_type_from_expr(arena, expr); E_IRNode *root = e_push_irnode(arena, RDI_EvalOp_ByteSwap); e_irnode_push_child(root, irtree.root); - E_IRTreeAndType result = {root, irtree.type_key, irtree.member, irtree.mode, irtree.msgs}; + E_IRTreeAndType result = {root, irtree.type_key, irtree.mode, irtree.msgs}; return result; } @@ -1793,6 +1792,246 @@ e_expr_unpoison(E_Expr *expr) } } +//- rjf: default type access hook + +E_TYPE_ACCESS_FUNCTION_DEF(default) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + switch(expr->kind) + { + default:{}break; + + //- rjf: member accessing (. operator) + case E_ExprKind_MemberAccess: + { + // rjf: unpack left/right expressions + E_Expr *exprl = expr->first; + E_Expr *exprr = exprl->next; + E_IRTreeAndType l = *lhs_irtree; + E_TypeKey l_restype = e_type_unwrap(l.type_key); + E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); + E_TypeKey check_type_key = l_restype; + E_TypeKind check_type_kind = l_restype_kind; + if(l_restype_kind == E_TypeKind_Ptr || + l_restype_kind == E_TypeKind_LRef || + l_restype_kind == E_TypeKind_RRef) + { + check_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_restype))); + check_type_kind = e_type_kind_from_key(check_type_key); + } + e_msg_list_concat_in_place(&result.msgs, &l.msgs); + + // rjf: look up member + E_Member member = zero_struct; + B32 r_found = 0; + E_TypeKey r_type = zero_struct; + U64 r_value = 0; + String8 r_query_name = {0}; + B32 r_is_constant_value = 0; + { + Temp scratch = scratch_begin(&arena, 1); + E_Member match = e_type_member_from_key_name__cached(check_type_key, exprr->string); + member = match; + if(match.kind != E_MemberKind_Null) + { + r_found = 1; + r_type = match.type_key; + r_value = match.off; + } + if(match.kind == E_MemberKind_Query) + { + r_query_name = exprr->string; + } + if(match.kind == E_MemberKind_Null) + { + E_Type *type = e_type_from_key__cached(check_type_key); + if(type->enum_vals != 0) + { + String8 lookup_string = exprr->string; + String8 lookup_string_append_1 = push_str8f(scratch.arena, "%S_%S", type->name, lookup_string); + String8 lookup_string_append_2 = push_str8f(scratch.arena, "%S%S", type->name, lookup_string); + E_EnumVal *enum_val_match = 0; + for EachIndex(idx, type->count) + { + if(str8_match(type->enum_vals[idx].name, lookup_string, 0) || + str8_match(type->enum_vals[idx].name, lookup_string_append_1, 0) || + str8_match(type->enum_vals[idx].name, lookup_string_append_2, 0)) + { + enum_val_match = &type->enum_vals[idx]; + break; + } + } + if(enum_val_match != 0) + { + r_found = 1; + r_type = check_type_key; + r_value = enum_val_match->val; + r_is_constant_value = 1; + } + } + } + scratch_end(scratch); + } + + // rjf: bad conditions? -> error if applicable, exit + if(e_type_key_match(e_type_key_zero(), check_type_key)) + { + break; + } + else if(exprr->kind != E_ExprKind_LeafIdentifier) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Expected member name."); + break; + } + else if(!r_found) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Could not find a member named `%S`.", exprr->string); + break; + } + else if(check_type_kind != E_TypeKind_Struct && + check_type_kind != E_TypeKind_Class && + check_type_kind != E_TypeKind_Union && + check_type_kind != E_TypeKind_Enum) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot perform member access on this type."); + break; + } + + // rjf: generate + { + // rjf: build tree + E_IRNode *new_tree = l.root; + E_TypeKey new_tree_type = r_type; + E_Mode mode = l.mode; + if(l_restype_kind == E_TypeKind_Ptr || + l_restype_kind == E_TypeKind_LRef || + l_restype_kind == E_TypeKind_RRef) + { + new_tree = e_irtree_resolve_to_value(arena, l.mode, new_tree, l_restype); + mode = E_Mode_Offset; + } + if(r_value != 0 && !r_is_constant_value) + { + E_IRNode *const_tree = e_irtree_const_u(arena, r_value); + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, new_tree, const_tree); + } + else if(r_is_constant_value) + { + new_tree = e_irtree_const_u(arena, r_value); + mode = E_Mode_Value; + } + + // rjf: fill + result.root = new_tree; + result.type_key = r_type; + result.mode = mode; + } + }break; + + //- rjf: indexing ([] operator) + case E_ExprKind_ArrayIndex: + { + // rjf: unpack left/right expressions + E_Expr *exprl = expr->first; + E_Expr *exprr = exprl->next; + E_IRTreeAndType l = *lhs_irtree; + E_IRTreeAndType r = e_irtree_and_type_from_expr(arena, exprr); + E_TypeKey l_restype = e_type_unwrap(l.type_key); + E_TypeKey r_restype = e_type_unwrap(r.type_key); + E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); + E_TypeKind r_restype_kind = e_type_kind_from_key(r_restype); + if(e_type_kind_is_basic_or_enum(r_restype_kind)) + { + r_restype = e_type_unwrap_enum(r_restype); + r_restype_kind = e_type_kind_from_key(r_restype); + } + E_TypeKey direct_type = e_type_unwrap(l_restype); + direct_type = e_type_direct_from_key(direct_type); + direct_type = e_type_unwrap(direct_type); + U64 direct_type_size = e_type_byte_size_from_key(direct_type); + e_msg_list_concat_in_place(&result.msgs, &l.msgs); + e_msg_list_concat_in_place(&result.msgs, &r.msgs); + + // rjf: bad conditions? -> error if applicable, exit + if(r.root->op == 0) + { + break; + } + else if(l_restype_kind != E_TypeKind_Ptr && l_restype_kind != E_TypeKind_Array) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot index into this type."); + break; + } + else if(!e_type_kind_is_integer(r_restype_kind)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index with this type."); + break; + } + else if(l_restype_kind == E_TypeKind_Ptr && direct_type_size == 0) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types."); + break; + } + else if(l_restype_kind == E_TypeKind_Array && direct_type_size == 0) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into arrays of zero-sized types."); + break; + } + + // rjf: generate + E_IRNode *new_tree = &e_irnode_nil; + E_Mode mode = l.mode; + { + // rjf: reading from an array value -> read from stack value + if(l.mode == E_Mode_Value && l_restype_kind == E_TypeKind_Array) + { + // rjf: ops to compute the offset + E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.mode, r.root, r_restype); + if(direct_type_size > 1) + { + E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + } + + // rjf: ops to push stack value, push offset, + read from stack value + new_tree = e_push_irnode(arena, RDI_EvalOp_ValueRead); + new_tree->value.u64 = direct_type_size; + e_irnode_push_child(new_tree, offset_tree); + e_irnode_push_child(new_tree, l.root); + } + + // rjf: all other cases -> read from base offset + else + { + // rjf: ops to compute the offset + E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.mode, r.root, r_restype); + if(direct_type_size > 1) + { + E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + } + + // rjf: ops to compute the base offset (resolve to value if addr-of-pointer) + E_IRNode *base_tree = l.root; + if(l_restype_kind == E_TypeKind_Ptr && l.mode != E_Mode_Value) + { + base_tree = e_irtree_resolve_to_value(arena, l.mode, base_tree, l_restype); + } + + // rjf: ops to compute the final address + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, offset_tree, base_tree); + } + } + + // rjf: fill + result.root = new_tree; + result.type_key = direct_type; + result.mode = mode; + }break; + } + return result; +} + //- rjf: top-level irtree/type extraction E_IRGEN_FUNCTION_DEF(default) @@ -1807,18 +2046,20 @@ E_IRGEN_FUNCTION_DEF(default) case E_ExprKind_MemberAccess: case E_ExprKind_ArrayIndex: { - Temp scratch = scratch_begin(&arena, 1); + // rjf: unpack left-hand-size E_Expr *lhs = expr->first; - E_Expr *rhs = lhs->next; - E_IRTreeAndType lhs_irtree = e_irtree_and_type_from_expr(scratch.arena, lhs); - E_LookupRule *lhs_lookup_rule = e_lookup_rule_from_type_key(lhs_irtree.type_key); - ProfScope("lookup via rule '%.*s'", str8_varg(lhs_lookup_rule->name)) + E_IRTreeAndType lhs_irtree = e_irtree_and_type_from_expr(arena, lhs); + + // rjf: pick access hook based on type + E_Type *lhs_type = e_type_from_key__cached(lhs_irtree.type_key); + E_TypeAccessFunctionType *lhs_access = lhs_type->access; + if(lhs_access == 0) { - E_LookupInfo lookup_info = lhs_lookup_rule->info(arena, &lhs_irtree, &e_expr_nil, str8_zero()); - E_LookupAccess lookup_access = lhs_lookup_rule->access(arena, expr->kind, lhs, rhs, &e_expr_nil, lookup_info.user_data); - result = lookup_access.irtree_and_type; + lhs_access = E_TYPE_ACCESS_FUNCTION_NAME(default); } - scratch_end(scratch); + + // rjf: call into hook to do access + result = lhs_access(arena, expr, &lhs_irtree); }break; //- rjf: dereference diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index b8acbc35..ee2944e9 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -625,14 +625,19 @@ e_type_from_key(Arena *arena, E_TypeKey key) if(e_type_key_match(node->key, key)) { type = push_array(arena, E_Type, 1); - type->kind = e_type_kind_from_key(node->key); - type->flags = node->params.flags; - type->name = push_str8_copy(arena, node->params.name); - type->direct_type_key = node->params.direct_key; - type->count = node->params.count; - type->depth = node->params.depth; - type->arch = node->params.arch; - type->byte_size = node->byte_size; + type->kind = e_type_kind_from_key(node->key); + type->flags = node->params.flags; + type->name = push_str8_copy(arena, node->params.name); + type->direct_type_key = node->params.direct_key; + type->count = node->params.count; + type->depth = node->params.depth; + type->arch = node->params.arch; + type->access = node->params.access; + type->expand_info = node->params.expand_info; + type->expand_range = node->params.expand_range; + type->expand_id_from_num = node->params.expand_id_from_num; + type->expand_num_from_id = node->params.expand_num_from_id; + type->byte_size = node->byte_size; switch(type->kind) { default:{}break; diff --git a/src/eval/eval_types.h b/src/eval/eval_types.h index 0ff334ed..9c94c2e8 100644 --- a/src/eval/eval_types.h +++ b/src/eval/eval_types.h @@ -47,6 +47,11 @@ struct E_ConsTypeParams E_Member *members; E_EnumVal *enum_vals; E_Expr **args; + E_TypeAccessFunctionType *access; + E_TypeExpandInfoFunctionType *expand_info; + E_TypeExpandRangeFunctionType *expand_range; + E_TypeExpandIDFromNumFunctionType *expand_id_from_num; + E_TypeExpandNumFromIDFunctionType *expand_num_from_id; }; typedef struct E_ConsTypeNode E_ConsTypeNode; diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 9985339d..634fc015 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -1406,7 +1406,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla case E_ExprKind_MemberAccess: { Temp scratch = scratch_begin(&arena, 1); - E_Member member = result.eval.irtree.member; + E_Member member = e_type_member_from_key_name__cached(result.eval.irtree.type_key, notable_expr->last->string); String8 member_name = member.name; if(member_name.size == 0) {