From 5103252a1ba7ef1ef51942de4cfe96acc92f4aee Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 26 Apr 2025 10:27:21 -0700 Subject: [PATCH] eliminate watches as a top-level entity, nest watch expressions under tabs - allow many watch windows, each with their own set of expressions. --- src/raddbg/generated/raddbg.meta.c | 4 +- src/raddbg/generated/raddbg.meta.h | 34 ++--- src/raddbg/raddbg.mdesk | 42 +++--- src/raddbg/raddbg_core.c | 35 ++--- src/raddbg/raddbg_eval.c | 216 +++++++++++++++-------------- src/raddbg/raddbg_eval.h | 18 +-- 6 files changed, 184 insertions(+), 165 deletions(-) diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index ead90914..672c4b0a 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -30,7 +30,7 @@ str8_lit_comp("memory"), String8 rd_tab_fast_path_query_name_table[20] = { -str8_lit_comp("query:watches"), +str8_lit_comp(""), str8_lit_comp("query:locals"), str8_lit_comp("query:registers"), str8_lit_comp("query:globals"), @@ -378,7 +378,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[21] = {str8_lit_comp("project"), str8_lit_comp("x:\n{\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n}\n")}, {str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n}\n")}, {str8_lit_comp("tab"), str8_lit_comp("x:\n{\n @default(11) @display_name('Tab Font Size') @description(\"Controls the tab's font size.\")\n 'font_size': @range[6, 72] u64,\n}\n")}, -{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @default(3.f) @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': code_string,\n}\n")}, +{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @default(3.f) @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': code_string,\n @no_expand 'watches': query,\n}\n")}, {str8_lit_comp("text"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': lang,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': code_string,\n}\n")}, {str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': code_string,\n 'arch': arch,\n 'syntax': dasm_syntax,\n 'size': code_string,\n @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")}, {str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the memory view.\")\n 'expression': code_string,\n @description(\"The number of bytes of the viewed memory range.\")\n 'size': code_string,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n @default(1) @description(\"The number of bytes that each cell should represent.\")\n 'bytes_per_cell': @range[1, 8] u64,\n}\n")}, diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index 046029f5..3bf7d01c 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -600,23 +600,23 @@ RD_Query query; }; #define RD_FixedTabXList \ -X(watches)\ -X(locals)\ -X(registers)\ -X(globals)\ -X(thread_locals)\ -X(types)\ -X(procedures)\ -X(call_stack)\ -X(targets)\ -X(breakpoints)\ -X(watch_pins)\ -X(threads)\ -X(processes)\ -X(machines)\ -X(modules)\ -X(file_path_maps)\ -X(auto_view_rules)\ +Y(watches, watch, "")\ +X(locals) \ +X(registers) \ +X(globals) \ +X(thread_locals) \ +X(types) \ +X(procedures) \ +X(call_stack) \ +X(targets) \ +X(breakpoints) \ +X(watch_pins) \ +X(threads) \ +X(processes) \ +X(machines) \ +X(modules) \ +X(file_path_maps) \ +X(auto_view_rules) \ Y(output, text, "query:output")\ Y(disasm, disasm, "")\ Y(memory, memory, "")\ diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index ce97c431..c129ec95 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -14,26 +14,26 @@ //////////////////////////////// //~ rjf: Fixed Tab Tables -@table(name display_name name_lower icon) +@table(name display_name name_lower is_query icon) RD_WatchTabFastPathTable: { - {Watch "Watch" watches Binoculars } - {Locals "Locals" locals Binoculars } - {Registers "Registers" registers Binoculars } - {Globals "Globals" globals Binoculars } - {ThreadLocals "Thread Locals" thread_locals Binoculars } - {Types "Types" types Binoculars } - {Procedures "Procedures" procedures Binoculars } - {CallStack "Call Stack" call_stack Thread } - {Targets "Targets" targets Target } - {Breakpoints "Breakpoints" breakpoints CircleFilled } - {WatchPins "Watch Pins" watch_pins Pin } - {Threads "Threads" threads Threads } - {Processes "Processes" processes Scheduler } - {Machines "Machines" machines Machine } - {Modules "Modules" modules Module } - {FilePathMaps "File Path Map" file_path_maps FileOutline } - {AutoViewRules "Auto View Rules" auto_view_rules Binoculars } + {Watch "Watch" watches 0 Binoculars } + {Locals "Locals" locals 1 Binoculars } + {Registers "Registers" registers 1 Binoculars } + {Globals "Globals" globals 1 Binoculars } + {ThreadLocals "Thread Locals" thread_locals 1 Binoculars } + {Types "Types" types 1 Binoculars } + {Procedures "Procedures" procedures 1 Binoculars } + {CallStack "Call Stack" call_stack 1 Thread } + {Targets "Targets" targets 1 Target } + {Breakpoints "Breakpoints" breakpoints 1 CircleFilled } + {WatchPins "Watch Pins" watch_pins 1 Pin } + {Threads "Threads" threads 1 Threads } + {Processes "Processes" processes 1 Scheduler } + {Machines "Machines" machines 1 Machine } + {Modules "Modules" modules 1 Module } + {FilePathMaps "File Path Map" file_path_maps 1 FileOutline } + {AutoViewRules "Auto View Rules" auto_view_rules 1 Binoculars } } @table(name display_name name_lower view query icon) @@ -53,7 +53,7 @@ RD_FixedTabTable: @gen { `#define RD_FixedTabXList \\`; - @expand(RD_WatchTabFastPathTable a) `X($(a.name_lower))\\`; + @expand(RD_WatchTabFastPathTable a) `$(a.is_query -> 'X(' .. a.name_lower .. ')') $(a.is_query == 0 -> 'Y(' .. a.name_lower .. ', watch, ""' .. ')')\\`; @expand(RD_ViewTabFastPathTable a) `Y($(a.name_lower), $(a.view), "$(a.query)")\\`; @expand(RD_FixedTabTable a) `Z($(a.name_lower))\\`; ``; @@ -67,7 +67,7 @@ RD_FixedTabTable: @data(String8) rd_tab_fast_path_query_name_table: { - @expand(RD_WatchTabFastPathTable a) `str8_lit_comp("query:$(a.name_lower)")`, + @expand(RD_WatchTabFastPathTable a) `str8_lit_comp("$(a.is_query -> 'query:' .. a.name_lower)")`, @expand(RD_ViewTabFastPathTable a) `str8_lit_comp("$(a.query)")`, } @@ -315,8 +315,10 @@ RD_VocabTable: { @default(3.f) @display_name('Tab Row Height') @description("Controls the tab's row height, in multiples of the font size.") 'row_height': @range[1.75f, 5.f] f32, + 'label': code_string, @description("The root expression which is evaluated to produce the watch window.") 'expression': code_string, + @no_expand 'watches': query, } ``` } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 2821b1e7..908c0dff 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -2721,6 +2721,10 @@ rd_view_ui(Rng2F32 rect) Temp scratch = scratch_begin(0, 0); RD_Font(RD_FontSlot_Code) { + if(expr_string.size == 0) + { + expr_string = push_str8f(scratch.arena, "query:config.$%I64x.watches", rd_regs()->view); + } E_Eval eval = e_eval_from_string(expr_string); RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState); UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); @@ -3412,7 +3416,7 @@ rd_view_ui(Rng2F32 rect) if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) { RD_Cfg *cfg = row_info.group_cfg_child; - String8 child_key = str8_lit("expression"); + String8 child_key = {0}; // str8_lit("expression"); if(cfg == &rd_nil_cfg && editing_complete && new_string.size != 0) { RD_Cfg *new_cfg_parent = row_info.group_cfg_parent; @@ -11981,22 +11985,6 @@ rd_frame(void) } } - //- rjf: add macro for watches group - { - String8 collection_name = str8_lit("watches"); - E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); - expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); - expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, .name = collection_name, .flags = E_TypeFlag_EditableChildren, - .expand = - { - .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(watches), - .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(watches), - .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches), - .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches), - }); - e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); - } - //- rjf: add macros for all watches which define identifiers RD_CfgList watches = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch")); for(RD_CfgNode *n = watches.first; n != 0; n = n->next) @@ -12205,6 +12193,19 @@ rd_frame(void) .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment), .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment), })); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watches"), + e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_EditableChildren, + .name = str8_lit("watches"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(watches), + .access = E_TYPE_ACCESS_FUNCTION_NAME(watches), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(watches), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(watches), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches), + })); e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("call_stack"), diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index 78327684..9c57e91c 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -84,107 +84,6 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands) } } -//////////////////////////////// -//~ rjf: `watches` Type Hooks - -E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches) -{ - E_TypeExpandInfo result = {0}; - Temp scratch = scratch_begin(&arena, 1); - { - RD_CfgList cfgs_list = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch")); - RD_CfgList cfgs_list__filtered = cfgs_list; - if(filter.size != 0) - { - MemoryZeroStruct(&cfgs_list__filtered); - for(RD_CfgNode *n = cfgs_list.first; n != 0; n = n->next) - { - String8 expr = rd_expr_from_cfg(n->v); - B32 passes_filter = 1; - if(filter.size != 0) - { - E_Eval eval = e_eval_from_string(expr); - E_Type *type = e_type_from_key__cached(eval.irtree.type_key); - if(type->kind != E_TypeKind_Set) - { - passes_filter = 0; - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, expr); - if(matches.count == matches.needle_part_count) - { - passes_filter = 1; - } - } - } - if(passes_filter) - { - rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, n->v); - } - } - } - RD_CfgArray *cfgs = push_array(arena, RD_CfgArray, 1); - cfgs[0] = rd_cfg_array_from_list(arena, &cfgs_list__filtered); - result.user_data = cfgs; - result.expr_count = cfgs->count + 1; - } - scratch_end(scratch); - return result; -} - -E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches) -{ - RD_CfgArray *cfgs = (RD_CfgArray *)user_data; - Rng1U64 legal_idx_range = r1u64(0, cfgs->count); - Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range); - U64 read_range_count = dim_1u64(read_range); - for(U64 idx = 0; idx < read_range_count; idx += 1) - { - U64 cfg_idx = read_range.min + idx; - if(cfg_idx < cfgs->count) - { - String8 expr_string = rd_cfg_child_from_string(cfgs->v[cfg_idx], str8_lit("expression"))->first->string; - evals_out[idx] = e_eval_from_string(expr_string); - } - } -} - -E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches) -{ - U64 id = 0; - RD_CfgArray *cfgs = (RD_CfgArray *)user_data; - if(1 <= num && num <= cfgs->count) - { - U64 idx = (num-1); - id = cfgs->v[idx]->id; - } - else if(num == cfgs->count+1) - { - id = max_U64; - } - return id; -} - -E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches) -{ - U64 num = 0; - RD_CfgArray *cfgs = (RD_CfgArray *)user_data; - if(id != 0 && id != max_U64) - { - for EachIndex(idx, cfgs->count) - { - if(cfgs->v[idx]->id == id) - { - num = idx+1; - break; - } - } - } - else if(id == max_U64) - { - num = cfgs->count + 1; - } - return num; -} - //////////////////////////////// //~ rjf: `locals` Type Hooks @@ -1028,6 +927,121 @@ E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment) return num; } +//////////////////////////////// +//~ rjf: `watches` Type Hooks + +typedef struct RD_WatchesAccel RD_WatchesAccel; +struct RD_WatchesAccel +{ + RD_CfgArray cfgs; +}; + +E_TYPE_IREXT_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + E_Space space = interpret.space; + RD_Cfg *target = rd_cfg_from_eval_space(space); + RD_CfgList env_strings = {0}; + for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("watch"), 0)) + { + rd_cfg_list_push(scratch.arena, &env_strings, child); + } + } + accel->cfgs = rd_cfg_array_from_list(arena, &env_strings); + scratch_end(scratch); + } + E_IRExt result = {accel}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(watches) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_ArrayIndex) + { + RD_WatchesAccel *accel = (RD_WatchesAccel *)lhs_irtree->user_data; + RD_CfgArray *cfgs = &accel->cfgs; + E_Value rhs_value = e_value_from_expr(expr->first->next); + if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count) + { + RD_Cfg *cfg = cfgs->v[rhs_value.u64]; + result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); + result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText); + result.mode = E_Mode_Offset; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *accel = (RD_WatchesAccel *)eval.irtree.user_data; + E_TypeExpandInfo result = {accel, accel->cfgs.count + 1}; + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + Rng1U64 legal_idx_range = r1u64(0, accel->cfgs.count); + Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + U64 cfg_idx = read_range.min + idx; + if(cfg_idx < accel->cfgs.count) + { + RD_Cfg *cfg = accel->cfgs.v[cfg_idx]; + evals_out[idx] = e_eval_from_string(cfg->first->string); + } + } +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches) +{ + U64 id = 0; + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + if(1 <= num && num <= accel->cfgs.count) + { + U64 idx = (num-1); + id = accel->cfgs.v[idx]->id; + } + else if(num == accel->cfgs.count+1) + { + id = max_U64; + } + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches) +{ + U64 num = 0; + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + if(id != 0 && id != max_U64) + { + for EachIndex(idx, accel->cfgs.count) + { + if(accel->cfgs.v[idx]->id == id) + { + num = idx+1; + break; + } + } + } + else if(id == max_U64) + { + num = accel->cfgs.count + 1; + } + return num; +} + //////////////////////////////// //~ rjf: `unattached_processes` Type Hooks diff --git a/src/raddbg/raddbg_eval.h b/src/raddbg/raddbg_eval.h index 91295bea..41715697 100644 --- a/src/raddbg/raddbg_eval.h +++ b/src/raddbg/raddbg_eval.h @@ -11,14 +11,6 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands); E_TYPE_ACCESS_FUNCTION_DEF(commands); E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands); -//////////////////////////////// -//~ rjf: `watches` Type Hooks - -E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches); -E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches); -E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches); -E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches); - //////////////////////////////// //~ rjf: `locals` Type Hooks @@ -71,6 +63,16 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(environment); E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(environment); E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment); +//////////////////////////////// +//~ rjf: `watches` Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(watches); +E_TYPE_ACCESS_FUNCTION_DEF(watches); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches); + //////////////////////////////// //~ rjf: `unattached_processes` Type Hooks