From cb8f2749d9ca09d88c9f4342a28f92d29ef9b899 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Thu, 14 May 2026 14:34:17 -0700 Subject: [PATCH] source/disassembly inline auto expressions --- src/raddbg/generated/raddbg.meta.c | 2 +- src/raddbg/raddbg.mdesk | 4 + src/raddbg/raddbg_core.c | 176 +++++++++++++++++++++++++++++ src/raddbg/raddbg_core.h | 5 + src/raddbg/raddbg_eval.c | 175 +--------------------------- src/raddbg/raddbg_widgets.c | 144 +++++++++++++---------- 6 files changed, 273 insertions(+), 233 deletions(-) diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 32111c53..19b877bb 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -427,7 +427,7 @@ RD_VocabInfo rd_vocab_info_table[359] = RD_NameSchemaInfo rd_name_schema_info_table[39] = { -{str8_lit_comp("user"), 0, str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': set,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: scope decorations\n @default(1) @display_name('Cursor Scope Lines') @description(\"Controls whether or not scopes containing the cursor in text views are drawn.\")\n 'cursor_scope_lines': bool,\n @default(1) @display_name('Cursor Scope End Annotations') @description(\"Controls whether or not ending annotations for scopes containing the cursor are drawn.\")\n 'cursor_scope_end_annotations': bool,\n\n //- rjf: cursor decorations\n @default(1) @display_name('Cursor Trail') @description(\"Controls whether or not a movement trail of the cursor is drawn.\")\n 'cursor_trail': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n\n //- rjf: transient tabs\n @default(1) @display_name('Transient Tabs') @description(\"When snapping to source code locations, opens new files in a 'transient' tab if they are not already open. Transient tabs are replaced on subsequent snaps automatically.\")\n 'transient_tabs': bool,\n}\n")}, +{str8_lit_comp("user"), 0, str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': set,\n\n //- rjf: auto eval\n @display_name('Show Auto Watches In Source / Disassembly') @description(\"Enables the display of auto watch expressions inline in source and disassembly views.\") @default(1)\n 'show_autos_in_src_and_disasm': bool,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: scope decorations\n @default(1) @display_name('Cursor Scope Lines') @description(\"Controls whether or not scopes containing the cursor in text views are drawn.\")\n 'cursor_scope_lines': bool,\n @default(1) @display_name('Cursor Scope End Annotations') @description(\"Controls whether or not ending annotations for scopes containing the cursor are drawn.\")\n 'cursor_scope_end_annotations': bool,\n\n //- rjf: cursor decorations\n @default(1) @display_name('Cursor Trail') @description(\"Controls whether or not a movement trail of the cursor is drawn.\")\n 'cursor_trail': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n\n //- rjf: transient tabs\n @default(1) @display_name('Transient Tabs') @description(\"When snapping to source code locations, opens new files in a 'transient' tab if they are not already open. Transient tabs are replaced on subsequent snaps automatically.\")\n 'transient_tabs': bool,\n}\n")}, {str8_lit_comp("project"), 0, str8_lit_comp("@expand_commands(edit_project_theme) x:\n{\n @display_name('Project Name') 'name': string,\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: visualizers\n @display_name('Display Pointer Addresses Before Contents') @description(\"When visualizing pointers, always shows the address first, before showing contents at the pointer's address.\")\n @default(0) display_pointer_addresses_before_contents: bool,\n @display_name('Use Default C++ STL Type Visualizers') @description(\"Enables the built-in type views for C++ STL types.\")\n @default(1) use_default_stl_type_views: bool,\n @display_name('Use Default Unreal Engine Type Visualizers') @description(\"Enables the built-in type views for Unreal Engine types.\")\n @default(1) use_default_ue_type_views: bool,\n\n //- rjf: theme\n @default(\"None\") @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme': string,\n @no_expand @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme_colors': set,\n\n //- rjf: exception settings\n @default(1) @display_name(\"Break On Win32 Control-C Exceptions\") @description(\"Code: 0x40010005\")\n win32_ctrl_c: bool;\n @default(1) @display_name(\"Break On Win32 Control-Break Exceptions\") @description(\"Code: 0x40010008\")\n win32_ctrl_break: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Originate Error Exceptions\") @description(\"Code: 0x40080201\")\n win32_win_rt_originate_error: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Transform Error Exceptions\") @description(\"Code: 0x40080202\")\n win32_win_rt_transform_error: bool;\n @default(0) @display_name(\"Break On Win32 RPC Call Cancelled Exceptions\") @description(\"Code: 0x0000071a\")\n win32_rpc_call_cancelled: bool;\n @default(0) @display_name(\"Break On Win32 Data Type Misalignment Exceptions\") @description(\"Code: 0x80000002\")\n win32_datatype_misalignment: bool;\n @default(1) @display_name(\"Break On Win32 Access Violation Exceptions\") @description(\"Code: 0xc0000005\")\n win32_access_violation: bool;\n @default(0) @display_name(\"Break On Win32 In Page Error Exceptions\") @description(\"Code: 0xc0000006\")\n win32_in_page_error: bool;\n @default(1) @display_name(\"Break On Win32 Invalid Handle Specified Exceptions\") @description(\"Code: 0xc0000008\")\n win32_invalid_handle: bool;\n @default(0) @display_name(\"Break On Win32 Not Enough Quota Exceptions\") @description(\"Code: 0xc0000017\")\n win32_not_enough_quota: bool;\n @default(0) @display_name(\"Break On Win32 Illegal Instruction Exceptions\") @description(\"Code: 0xc000001d\")\n win32_illegal_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Cannot Continue From Exception Exceptions\") @description(\"Code: 0xc0000025\")\n win32_cannot_continue_exception: bool;\n @default(0) @display_name(\"Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions\") @description(\"Code: 0xc0000026\")\n win32_invalid_exception_disposition: bool;\n @default(0) @display_name(\"Break On Win32 Array Bounds Exceeded Exceptions\") @description(\"Code: 0xc000008c\")\n win32_array_bounds_exceeded: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Denormal Operand Exceptions\") @description(\"Code: 0xc000008d\")\n win32_floating_point_denormal_operand: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Division By Zero Exceptions\") @description(\"Code: 0xc000008e\")\n win32_floating_point_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Inexact Result Exceptions\") @description(\"Code: 0xc000008f\")\n win32_floating_point_inexact_result: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Invalid Operation Exceptions\") @description(\"Code: 0xc0000090\")\n win32_floating_point_invalid_operation: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Overflow Exceptions\") @description(\"Code: 0xc0000091\")\n win32_floating_point_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Stack Check Exceptions\") @description(\"Code: 0xc0000092\")\n win32_floating_point_stack_check: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Underflow Exceptions\") @description(\"Code: 0xc0000093\")\n win32_floating_point_underflow: bool;\n @default(0) @display_name(\"Break On Win32 Integer Division By Zero Exceptions\") @description(\"Code: 0xc0000094\")\n win32_integer_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Integer Overflow Exceptions\") @description(\"Code: 0xc0000095\")\n win32_integer_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Privileged Instruction Exceptions\") @description(\"Code: 0xc0000096\")\n win32_privileged_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Stack Overflow Exceptions\") @description(\"Code: 0xc00000fd\")\n win32_stack_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Unable To Locate DLL Exceptions\") @description(\"Code: 0xc0000135\")\n win32_unable_to_locate_dll: bool;\n @default(0) @display_name(\"Break On Win32 Ordinal Not Found Exceptions\") @description(\"Code: 0xc0000138\")\n win32_ordinal_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Entry Point Not Found Exceptions\") @description(\"Code: 0xc0000139\")\n win32_entry_point_not_found: bool;\n @default(0) @display_name(\"Break On Win32 DLL Initialization Failed Exceptions\") @description(\"Code: 0xc0000142\")\n win32_dll_initialization_failed: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Faults Exceptions\") @description(\"Code: 0xc00002b4\")\n win32_floating_point_sse_multiple_faults: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Traps Exceptions\") @description(\"Code: 0xc00002b5\")\n win32_floating_point_sse_multiple_traps: bool;\n @default(1) @display_name(\"Break On Win32 Assertion Failed Exceptions\") @description(\"Code: 0xc0000420\")\n win32_assertion_failed: bool;\n @default(0) @display_name(\"Break On Win32 Module Not Found Exceptions\") @description(\"Code: 0xc06d007e\")\n win32_module_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Procedure Not Found Exceptions\") @description(\"Code: 0xc06d007f\")\n win32_procedure_not_found: bool;\n @default(1) @display_name(\"Break On Win32 Sanitizer Error Detected Exceptions\") @description(\"Code: 0xe073616e\")\n win32_sanitizer_error_detected: bool;\n @default(0) @display_name(\"Break On Win32 Sanitizer Raw Access Violation Exceptions\") @description(\"Code: 0xe0736171\")\n win32_sanitizer_raw_access_violation: bool;\n @default(1) @display_name(\"Break On Win32 DirectX Debug Layer Exceptions\") @description(\"Code: 0x0000087a\")\n win32_directx_debug_layer: bool;\n}\n")}, {str8_lit_comp("theme_color"), 0, str8_lit_comp("@collection_commands(add_theme_color, fork_theme, save_theme, save_and_set_theme)\n@row_commands(duplicate_cfg, remove_cfg)\nx:\n{\n @display_name('Tags') tags: string,\n @display_name('Value') value: @color @hex u32,\n}\n")}, {str8_lit_comp("window"), 0, 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 //- rjf: theme settings\n @default(1) @display_name('Use Project Theme') @description(\"Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.\")\n 'use_project_theme': bool,\n}\n")}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 233870b5..59240a09 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -255,6 +255,10 @@ RD_VocabTable: @no_expand @display_name('User Theme') 'theme_colors': set, + //- rjf: auto eval + @display_name('Show Auto Watches In Source / Disassembly') @description("Enables the display of auto watch expressions inline in source and disassembly views.") @default(1) + 'show_autos_in_src_and_disasm': bool, + //- rjf: autocompletion @display_name('Autocompletion Lister') @description("Enables the autocompletion lister while typing expressions.") @default(1) 'autocompletion_lister': bool, diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index cdcef522..597295d6 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -9821,6 +9821,182 @@ rd_vocab_info_from_code_name_plural(String8 code_name_plural) return result; } +//////////////////////////////// +//~ rjf: Auto Watch Computation + +internal String8Array +rd_gather_auto_exprs(Arena *arena) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List auto_exprs = {0}; + ProfScope("compute all autos") + { + Access *access = access_open(); + U64 seen_expr_slots_count = 16; + String8Node **seen_expr_slots = push_array(scratch.arena, String8Node *, seen_expr_slots_count); + D_Handle thread_handle = rd_regs()->thread; + D_Entity *thread = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, thread_handle); + D_CallStack call_stack = d_call_stack_from_thread(access, thread->handle, 0, 0); + if(call_stack.frames_count != 0) + { + //- rjf: unpack thread / module / debug info / lines + ARCH_Info *arch_info = arch_info_from_arch(thread->arch); + D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); + U64 thread_ip_vaddr = d_rip_from_thread(&d_user_state->ctrl_entity_store->ctx, thread_handle); + D_Entity *module = d_module_from_process_vaddr(process, thread_ip_vaddr); + DI_Key dbgi_key = d_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); + U64 thread_ip_voff = d_voff_from_vaddr(module, thread_ip_vaddr); + D_LineList thread_ip_lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, thread_ip_voff); + + //- rjf: gather all relevant code vaddr ranges + Rng1U64List code_vaddr_ranges = {0}; + { + U64 line_range_limit = 0; + for EachNode(n, D_LineNode, thread_ip_lines.first) + { + Rng1U64 line_voff_range = n->v.voff_range; + Rng1U64 line_vaddr_range = d_vaddr_range_from_voff_range(module, line_voff_range); + rng1u64_list_push(scratch.arena, &code_vaddr_ranges, line_vaddr_range); + line_range_limit += 1; + if(line_range_limit >= 16) + { + break; + } + } + rng1u64_list_push(scratch.arena, &code_vaddr_ranges, rd_state->autos_determining_vaddr_range); + } + + //- rjf: for each code vaddr range -> disassemble, look at src/dest of instructions, + // map back to location info, & gather expressions for affected symbols + for EachNode(n, Rng1U64Node, code_vaddr_ranges.first) + { + Rng1U64 vaddr_range = n->v; + vaddr_range.max = Min(vaddr_range.min+64, vaddr_range.max); + D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, vaddr_range, 0, 0); + for(U64 off = 0, next_off = 0; off < slice.data.size; off = next_off) + { + next_off = slice.data.size; + + // rjf: disassemble next instruction + DASM_Inst inst = dasm_inst_from_code(scratch.arena, thread->arch, vaddr_range.min + off, str8_skip(slice.data, off), DASM_Syntax_Intel); + next_off = off + inst.size; + + // rjf: gather locations from instruction + struct + { + ARCH_RegCode reg_code; + U64 reg_off; + } + inst_locations[] = + { + {inst.dst_reg_code, inst.dst_reg_off}, + {inst.src_reg_code, inst.src_reg_off}, + }; + + // rjf: for each location -> map to symbols, gather + for EachElement(location_idx, inst_locations) + { + if(inst_locations[location_idx].reg_code != 0) + { + U64 reg_value = 0; + void *regs = call_stack.frames[0].regs; + Rng1U16 reg_rng = arch_info->reg_code_rng_table[inst_locations[location_idx].reg_code]; + reg_rng.max = Min(reg_rng.max, reg_rng.min + sizeof(reg_value)); + if(arch_reg_block_read_range(arch_info, regs, reg_rng, ®_value)) + { + U64 affected_vaddr = reg_value + inst_locations[location_idx].reg_off; + + // rjf: compare against locals + { + E_String2NumMap *locals_map = e_ir_ctx->locals_map; + for(E_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) + { + U64 local_num = n->num; + if(local_num != 0) + { + U64 local_idx = local_num-1; + RDI_Symbol *local = rdi_element_from_name_idx(rdi, LocalVariables, local_idx); + if(rdi_kind_from_location(local->location) == RDI_LocationKind_AddrBytecodeStream || + rdi_kind_from_location(local->location) == RDI_LocationKind_AddrRegPlusOff || + rdi_kind_from_location(local->location) == RDI_LocationKind_AddrAddrRegPlusOff) + { + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local->type_idx); + E_OpList local_ops = e_oplist_from_location(scratch.arena, rdi, local->location); + String8 local_bytecode = e_bytecode_from_oplist(scratch.arena, &local_ops); + E_Interpretation local_addr_interpret = e_interpret(local_bytecode); + U64 local_vaddr = local_addr_interpret.value.u64; + Rng1U64 local_vaddr_range = r1u64(local_vaddr, local_vaddr+type_node->byte_size); + if(contains_1u64(local_vaddr_range, affected_vaddr)) + { + String8 local_name = str8_from_rdi_string_idx(rdi, local->name_string_idx); + U64 hash = u64_hash_from_str8(local_name); + U64 slot_idx = hash%seen_expr_slots_count; + B32 already_seen = 0; + for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next) + { + if(str8_match(n->string, local_name, 0)) + { + already_seen = 1; + break; + } + } + if(!already_seen) + { + str8_list_push(scratch.arena, &auto_exprs, local_name); + String8Node *n = push_array(scratch.arena, String8Node, 1); + SLLStackPush(seen_expr_slots[slot_idx], n); + n->string = local_name; + } + } + } + } + } + } + + // rjf: compare against global variables + { + D_Entity *affected_module = d_module_from_process_vaddr(process, affected_vaddr); + U64 affected_voff = d_voff_from_vaddr(affected_module, affected_vaddr); + DI_Key affected_dbgi_key = d_dbgi_key_from_module(affected_module); + RDI_Parsed *affected_rdi = di_rdi_from_key(access, affected_dbgi_key, 0, 0); + RDI_Symbol *affected_gvar = rdi_global_variable_from_voff(affected_rdi, affected_voff); + if(affected_gvar->name_string_idx != 0) + { + String8 gvar_name = fully_qualified_str8_from_rdi_symbol(arena, affected_rdi, affected_gvar); + U64 hash = u64_hash_from_str8(gvar_name); + U64 slot_idx = hash%seen_expr_slots_count; + B32 already_seen = 0; + for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next) + { + if(str8_match(n->string, gvar_name, 0)) + { + already_seen = 1; + break; + } + } + if(!already_seen) + { + str8_list_push(scratch.arena, &auto_exprs, gvar_name); + String8Node *n = push_array(scratch.arena, String8Node, 1); + SLLStackPush(seen_expr_slots[slot_idx], n); + n->string = gvar_name; + } + } + } + } + } + } + } + } + } + access_close(access); + } + String8Array result = str8_array_from_list(arena, &auto_exprs); + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: Continuous Frame Requests diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 451eb84c..e278f87e 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -794,6 +794,11 @@ internal RD_VocabInfo *rd_vocab_info_from_code_name_plural(String8 code_name_plu #define rd_icon_kind_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->icon_kind) #define rd_singular_from_code_name_plural(code_name_plural) (rd_vocab_info_from_code_name_plural(code_name_plural)->code_name) +//////////////////////////////// +//~ rjf: Auto Watch Computation + +internal String8Array rd_gather_auto_exprs(Arena *arena); + //////////////////////////////// //~ rjf: Continuous Frame Requests diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c index fa93bc19..c911fbaf 100644 --- a/src/raddbg/raddbg_eval.c +++ b/src/raddbg/raddbg_eval.c @@ -319,182 +319,9 @@ E_TYPE_IREXT_FUNCTION_DEF(autos) { E_IRExt irext = {0}; { - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: compute all autos - String8List auto_exprs = {0}; - ProfScope("compute all autos") - { - Access *access = access_open(); - U64 seen_expr_slots_count = 16; - String8Node **seen_expr_slots = push_array(scratch.arena, String8Node *, seen_expr_slots_count); - D_Handle thread_handle = rd_regs()->thread; - D_Entity *thread = d_entity_from_handle(&d_user_state->ctrl_entity_store->ctx, thread_handle); - D_CallStack call_stack = d_call_stack_from_thread(access, thread->handle, 0, 0); - if(call_stack.frames_count != 0) - { - //- rjf: unpack thread / module / debug info / lines - ARCH_Info *arch_info = arch_info_from_arch(thread->arch); - D_Entity *process = d_entity_ancestor_from_kind(thread, D_EntityKind_Process); - U64 thread_ip_vaddr = d_rip_from_thread(&d_user_state->ctrl_entity_store->ctx, thread_handle); - D_Entity *module = d_module_from_process_vaddr(process, thread_ip_vaddr); - DI_Key dbgi_key = d_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0); - U64 thread_ip_voff = d_voff_from_vaddr(module, thread_ip_vaddr); - D_LineList thread_ip_lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, thread_ip_voff); - - //- rjf: gather all relevant code vaddr ranges - Rng1U64List code_vaddr_ranges = {0}; - { - U64 line_range_limit = 0; - for EachNode(n, D_LineNode, thread_ip_lines.first) - { - Rng1U64 line_voff_range = n->v.voff_range; - Rng1U64 line_vaddr_range = d_vaddr_range_from_voff_range(module, line_voff_range); - rng1u64_list_push(scratch.arena, &code_vaddr_ranges, line_vaddr_range); - line_range_limit += 1; - if(line_range_limit >= 16) - { - break; - } - } - rng1u64_list_push(scratch.arena, &code_vaddr_ranges, rd_state->autos_determining_vaddr_range); - } - - //- rjf: for each code vaddr range -> disassemble, look at src/dest of instructions, - // map back to location info, & gather expressions for affected symbols - for EachNode(n, Rng1U64Node, code_vaddr_ranges.first) - { - Rng1U64 vaddr_range = n->v; - vaddr_range.max = Min(vaddr_range.min+64, vaddr_range.max); - D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, vaddr_range, 0, 0); - for(U64 off = 0, next_off = 0; off < slice.data.size; off = next_off) - { - next_off = slice.data.size; - - // rjf: disassemble next instruction - DASM_Inst inst = dasm_inst_from_code(scratch.arena, thread->arch, vaddr_range.min + off, str8_skip(slice.data, off), DASM_Syntax_Intel); - next_off = off + inst.size; - - // rjf: gather locations from instruction - struct - { - ARCH_RegCode reg_code; - U64 reg_off; - } - inst_locations[] = - { - {inst.dst_reg_code, inst.dst_reg_off}, - {inst.src_reg_code, inst.src_reg_off}, - }; - - // rjf: for each location -> map to symbols, gather - for EachElement(location_idx, inst_locations) - { - if(inst_locations[location_idx].reg_code != 0) - { - U64 reg_value = 0; - void *regs = call_stack.frames[0].regs; - Rng1U16 reg_rng = arch_info->reg_code_rng_table[inst_locations[location_idx].reg_code]; - reg_rng.max = Min(reg_rng.max, reg_rng.min + sizeof(reg_value)); - if(arch_reg_block_read_range(arch_info, regs, reg_rng, ®_value)) - { - U64 affected_vaddr = reg_value + inst_locations[location_idx].reg_off; - - // rjf: compare against locals - { - E_String2NumMap *locals_map = e_ir_ctx->locals_map; - for(E_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) - { - U64 local_num = n->num; - if(local_num != 0) - { - U64 local_idx = local_num-1; - RDI_Symbol *local = rdi_element_from_name_idx(rdi, LocalVariables, local_idx); - if(rdi_kind_from_location(local->location) == RDI_LocationKind_AddrBytecodeStream || - rdi_kind_from_location(local->location) == RDI_LocationKind_AddrRegPlusOff || - rdi_kind_from_location(local->location) == RDI_LocationKind_AddrAddrRegPlusOff) - { - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local->type_idx); - E_OpList local_ops = e_oplist_from_location(scratch.arena, rdi, local->location); - String8 local_bytecode = e_bytecode_from_oplist(scratch.arena, &local_ops); - E_Interpretation local_addr_interpret = e_interpret(local_bytecode); - U64 local_vaddr = local_addr_interpret.value.u64; - Rng1U64 local_vaddr_range = r1u64(local_vaddr, local_vaddr+type_node->byte_size); - if(contains_1u64(local_vaddr_range, affected_vaddr)) - { - String8 local_name = str8_from_rdi_string_idx(rdi, local->name_string_idx); - U64 hash = u64_hash_from_str8(local_name); - U64 slot_idx = hash%seen_expr_slots_count; - B32 already_seen = 0; - for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, local_name, 0)) - { - already_seen = 1; - break; - } - } - if(!already_seen) - { - str8_list_push(scratch.arena, &auto_exprs, local_name); - String8Node *n = push_array(scratch.arena, String8Node, 1); - SLLStackPush(seen_expr_slots[slot_idx], n); - n->string = local_name; - } - } - } - } - } - } - - // rjf: compare against global variables - { - D_Entity *affected_module = d_module_from_process_vaddr(process, affected_vaddr); - U64 affected_voff = d_voff_from_vaddr(affected_module, affected_vaddr); - DI_Key affected_dbgi_key = d_dbgi_key_from_module(affected_module); - RDI_Parsed *affected_rdi = di_rdi_from_key(access, affected_dbgi_key, 0, 0); - RDI_Symbol *affected_gvar = rdi_global_variable_from_voff(affected_rdi, affected_voff); - if(affected_gvar->name_string_idx != 0) - { - String8 gvar_name = fully_qualified_str8_from_rdi_symbol(arena, affected_rdi, affected_gvar); - U64 hash = u64_hash_from_str8(gvar_name); - U64 slot_idx = hash%seen_expr_slots_count; - B32 already_seen = 0; - for(String8Node *n = seen_expr_slots[slot_idx]; n != 0; n = n->next) - { - if(str8_match(n->string, gvar_name, 0)) - { - already_seen = 1; - break; - } - } - if(!already_seen) - { - str8_list_push(scratch.arena, &auto_exprs, gvar_name); - String8Node *n = push_array(scratch.arena, String8Node, 1); - SLLStackPush(seen_expr_slots[slot_idx], n); - n->string = gvar_name; - } - } - } - } - } - } - } - } - } - access_close(access); - } - - //- rjf: gather RD_AutosAccel *accel = push_array(arena, RD_AutosAccel, 1); - { - accel->exprs = str8_array_from_list(arena, &auto_exprs); - } + accel->exprs = rd_gather_auto_exprs(arena); irext.user_data = accel; - - scratch_end(scratch); } return irext; } diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index da8f2c83..cd268b24 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -1266,30 +1266,31 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe B32 ctrlified = (wm_get_modifiers() & WM_Modifier_Ctrl); Vec4F32 code_line_bgs[] = { - ui_color_from_name(str8_lit("line_info_0")), - ui_color_from_name(str8_lit("line_info_1")), - ui_color_from_name(str8_lit("line_info_2")), - ui_color_from_name(str8_lit("line_info_3")), + ui_color_from_name(s("line_info_0")), + ui_color_from_name(s("line_info_1")), + ui_color_from_name(s("line_info_2")), + ui_color_from_name(s("line_info_3")), }; F32 line_num_padding_px = ui_top_font_size()*1.f; F32 entity_alive_t_rate = rd_state->entity_alive_animation_rate; F32 entity_hover_t_rate = rd_state->rich_hover_animation_rate; - B32 do_thread_lines = rd_setting_b32_from_name(str8_lit("thread_lines")); - B32 do_thread_glow = rd_setting_b32_from_name(str8_lit("thread_glow")); - B32 do_bp_lines = rd_setting_b32_from_name(str8_lit("breakpoint_lines")); - B32 do_bp_glow = rd_setting_b32_from_name(str8_lit("breakpoint_glow")); - B32 do_scope_lines = rd_setting_b32_from_name(str8_lit("cursor_scope_lines")); - B32 do_scope_end_annotations = rd_setting_b32_from_name(str8_lit("cursor_scope_end_annotations")); - B32 do_cursor_trail = rd_setting_b32_from_name(str8_lit("cursor_trail")); + B32 do_thread_lines = rd_setting_b32_from_name(s("thread_lines")); + B32 do_thread_glow = rd_setting_b32_from_name(s("thread_glow")); + B32 do_bp_lines = rd_setting_b32_from_name(s("breakpoint_lines")); + B32 do_bp_glow = rd_setting_b32_from_name(s("breakpoint_glow")); + B32 do_scope_lines = rd_setting_b32_from_name(s("cursor_scope_lines")); + B32 do_scope_end_annotations = rd_setting_b32_from_name(s("cursor_scope_end_annotations")); + B32 do_cursor_trail = rd_setting_b32_from_name(s("cursor_trail")); + B32 do_autos = rd_setting_b32_from_name(s("show_autos_in_src_and_disasm")); Vec4F32 pop_color = {0}; UI_TagF("pop") { - pop_color = ui_color_from_name(str8_lit("background")); + pop_color = ui_color_from_name(s("background")); } Vec4F32 highlight_color = {0}; UI_TagF("focus") { - highlight_color = ui_color_from_name(str8_lit("border")); + highlight_color = ui_color_from_name(s("border")); } ////////////////////////////// @@ -1325,8 +1326,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { CFG_Node *cfg = cfg_node_from_id(rd_state->drag_drop_regs->cfg); if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && - (str8_match(cfg->string, str8_lit("breakpoint"), 0) || - str8_match(cfg->string, str8_lit("watch_pin"), 0))) + (str8_match(cfg->string, s("breakpoint"), 0) || + str8_match(cfg->string, s("watch_pin"), 0))) { drop_can_hit_lines = 1; drop_cfg = cfg; @@ -1376,7 +1377,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { if(n->v == stopper_thread && (stop_event.cause == D_EventCause_InterruptedByTrap || stop_event.cause == D_EventCause_InterruptedByException)) { - line_bg_colors[line_idx] = ui_color_from_name(str8_lit("background")); + line_bg_colors[line_idx] = ui_color_from_name(s("background")); } } } @@ -1399,7 +1400,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_pref_width(ui_px(params->priority_margin_width_px, 1)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_child_layout_axis(Axis2_Y); - priority_margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("priority_margin_container")); + priority_margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), s("priority_margin_container")); UI_Parent(priority_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { U64 line_idx = 0; @@ -1433,18 +1434,18 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { if(color.w == 0) { - color = ui_color_from_name(str8_lit("thread_1")); + color = ui_color_from_name(s("thread_1")); } if(unwind_count != 0) { - color = ui_color_from_name(str8_lit("thread_unwound")); + color = ui_color_from_name(s("thread_unwound")); } else if(thread == stopper_thread && (stop_event.cause == D_EventCause_InterruptedByHalt || stop_event.cause == D_EventCause_InterruptedByTrap || stop_event.cause == D_EventCause_InterruptedByException)) { - color = ui_color_from_name(str8_lit("thread_error")); + color = ui_color_from_name(s("thread_error")); } if(d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index()) { @@ -1552,7 +1553,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_pref_width(ui_px(params->catchall_margin_width_px, 1)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_child_layout_axis(Axis2_Y); - catchall_margin_container_box = ui_build_box_from_string(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("catchall_margin_container")); + catchall_margin_container_box = ui_build_box_from_string(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), s("catchall_margin_container")); UI_Parent(catchall_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { U64 line_idx = 0; @@ -1589,18 +1590,18 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { if(color.w == 0) { - color = ui_color_from_name(str8_lit("thread_1")); + color = ui_color_from_name(s("thread_1")); } if(unwind_count != 0) { - color = ui_color_from_name(str8_lit("thread_unwound")); + color = ui_color_from_name(s("thread_unwound")); } else if(thread == stopper_thread && (stop_event.cause == D_EventCause_InterruptedByHalt || stop_event.cause == D_EventCause_InterruptedByTrap || stop_event.cause == D_EventCause_InterruptedByException)) { - color = ui_color_from_name(str8_lit("thread_error")); + color = ui_color_from_name(s("thread_error")); } if(d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index()) { @@ -1697,7 +1698,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe Vec4F32 bp_rgba = rd_color_from_cfg(bp); if(bp_rgba.w == 0) { - bp_rgba = ui_color_from_name(str8_lit("breakpoint")); + bp_rgba = ui_color_from_name(s("breakpoint")); } B32 bp_is_disabled = rd_disabled_from_cfg(bp); if(bp_is_disabled) @@ -1716,7 +1717,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe bp_draw->do_lines = do_bp_lines; bp_draw->do_glow = do_bp_glow; bp_draw->is_disabled = bp_is_disabled; - bp_draw->is_conditioned = (cfg_node_child_from_string(bp, str8_lit("condition"))->first->string.size != 0); + bp_draw->is_conditioned = (cfg_node_child_from_string(bp, s("condition"))->first->string.size != 0); if(params->line_vaddrs[line_idx] == 0) { D_LineList *lines = ¶ms->line_infos[line_idx]; @@ -1787,7 +1788,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe Vec4F32 color = rd_color_from_cfg(pin); if(color.w == 0) { - color = ui_color_from_name(str8_lit("code_default")); + color = ui_color_from_name(s("code_default")); } // rjf: build box for watch @@ -1918,7 +1919,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { ui_set_next_hover_cursor(ctrlified ? WM_Cursor_HandPoint : WM_Cursor_IBar); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); - text_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("text_container")); + text_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), s("text_container")); } ////////////////////////////// @@ -2055,7 +2056,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } rd_cmd(RD_CmdKind_FocusPanel); rd_cmd(RD_CmdKind_PushQuery, - .expr = txt_pt_match(*cursor, *mark) ? str8_lit("query:text_pt_commands") : str8_lit("query:text_range_commands"), + .expr = txt_pt_match(*cursor, *mark) ? s("query:text_pt_commands") : s("query:text_range_commands"), .do_implicit_root = 1, .do_lister = 1, .activate_with_single_click = 1, @@ -2227,20 +2228,20 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { String8 opener_line = str8_skip_chop_whitespace(txt_string_from_info_data_line_num(params->text_info, params->text_data, txt_range.min.line)); String8 scope_title_string = opener_line; - if(str8_match(opener_line, str8_lit("{"), 0) || - str8_match(opener_line, str8_lit("["), 0) || - str8_match(opener_line, str8_lit("("), 0)) + if(str8_match(opener_line, s("{"), 0) || + str8_match(opener_line, s("["), 0) || + str8_match(opener_line, s("("), 0)) { scope_title_string = str8_skip_chop_whitespace(txt_string_from_info_data_line_num(params->text_info, params->text_data, txt_range.min.line-1)); } - if(!str8_match(scope_title_string, str8_lit("{"), 0) && - !str8_match(scope_title_string, str8_lit("["), 0) && - !str8_match(scope_title_string, str8_lit("("), 0)) + if(!str8_match(scope_title_string, s("{"), 0) && + !str8_match(scope_title_string, s("["), 0) && + !str8_match(scope_title_string, s("("), 0)) { F32 t = ui_anim(ui_key_from_stringf(text_container_box->key, "###scope_end_annotation_%I64x_%I64x", scope_n->token_idx_range.min, scope_n->token_idx_range.max), 1.f, .rate = rd_state->catchall_animation_rate); String8 closer_line = txt_string_from_info_data_line_num(params->text_info, params->text_data, txt_range.max.line); F32 closer_line_px = fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, closer_line).x; - Vec4F32 color = ui_color_from_name(str8_lit("text")); + Vec4F32 color = ui_color_from_name(s("text")); color.w *= 0.5f*t; dr_text(params->font, params->font_size * 0.85f, 0, 0, ui_top_text_raster_flags(), v2f32(text_base_pos.x + closer_line_px + ui_top_font_size()*0.5f*t, @@ -2328,7 +2329,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe dr_fstrs_push_new(scratch.arena, &fstrs, &fstr_params, token_string, .color = token_color); // rjf: . -> mark next token as preceded by dot - preceded_by_dot = (token->kind == TXT_TokenKind_Symbol && str8_match(token_string, str8_lit("."), 0)); + preceded_by_dot = (token->kind == TXT_TokenKind_Symbol && str8_match(token_string, s("."), 0)); } } lines_fstrs[line_idx] = fstrs; @@ -2368,23 +2369,47 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } ////////////////////////////// - //- rjf: build watch pin annotations + //- rjf: build watch pin / auto annotations // UI_Focus(UI_FocusKind_Off) { + String8Array auto_exprs = {0}; + if(do_autos) + { + auto_exprs = rd_gather_auto_exprs(scratch.arena); + } U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; line_num < params->line_num_range.max; line_num += 1, line_idx += 1) { + //- rjf: gather pins from autos CFG_NodePtrList immediate_pins = {0}; + if(do_autos) + { + D_EntityList line_ips = params->line_ips[line_idx]; + if(line_ips.count > 0 && d_handle_match(line_ips.first->v->handle, rd_regs()->thread)) + { + for EachIndex(idx, auto_exprs.count) + { + String8 auto_expr = auto_exprs.v[idx]; + CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("auto_pin_%I64x_%S", ui_active_seed_key().u64[0], auto_expr); + CFG_Node *pin = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, s("watch_pin")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, pin, s("expression")); + cfg_node_new_replace(rd_state->cfg, expr, auto_expr); + cfg_node_ptr_list_push(scratch.arena, &immediate_pins, pin); + } + } + } + + //- rjf: gather pins from source String8 line_text = params->line_text[line_idx]; for(U64 off = 0, next_off = line_text.size; off < line_text.size; off = next_off) { // rjf: find next opener - String8 markup_opener = str8_lit("raddbg_pin("); + String8 markup_opener = s("raddbg_pin("); next_off = str8_find_needle(line_text, off, markup_opener, 0); next_off += markup_opener.size; @@ -2447,12 +2472,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe if(expr_string.size != 0) { CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off); - CFG_Node *pin = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, str8_lit("watch_pin")); - CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, pin, str8_lit("expression")); + CFG_Node *pin = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, s("watch_pin")); + CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, pin, s("expression")); cfg_node_new_replace(rd_state->cfg, expr, expr_string); cfg_node_ptr_list_push(scratch.arena, &immediate_pins, pin); } } + + //- rjf: build pin ui CFG_NodePtrList pin_lists[] = { params->line_pins[line_idx], @@ -2466,6 +2493,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe UI_FontSize(params->font_size) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { + F32 pin_value_string_max_width_px = params->font_size * (80.f / pins.count); for(CFG_NodePtrNode *n = pins.first; n != 0; n = n->next) { CFG_Node *pin = n->v; @@ -2475,28 +2503,26 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe if(!e_type_key_match(e_type_key_zero(), eval.irtree.type_key)) { EV_StringParams string_params = {.flags = EV_StringFlag_ReadOnlyDisplayRules|rd_state->eval_viz_base_string_flags, .radix = 10}; - eval_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, params->font, params->font_size, params->font_size*60.f, eval); + eval_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, params->font, params->font_size, pin_value_string_max_width_px, eval); } ui_spacer(ui_em(1.5f, 1.f)); ui_set_next_pref_width(ui_children_sum(1)); UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin); - UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos| - UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawBorder, pin_box_key); - UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1)) + UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos, pin_box_key); + F32 pin_t = ui_anim(pin_box_key, 1.f, .rate = rd_state->catchall_animation_rate); + UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(1, 1)) { Vec4F32 pin_color = rd_color_from_cfg(pin); if(pin_color.w == 0) { - pin_color = ui_color_from_name(str8_lit("text")); + pin_color = ui_color_from_name(s("text")); } - Vec4F32 default_code_color = ui_color_from_name(str8_lit("code_default")); - rd_code_label(0.8f, 1, default_code_color, pin_expr); - rd_code_label(0.6f, 1, default_code_color, eval_string); + Vec4F32 default_code_color = ui_color_from_name(s("code_default")); + rd_code_label(pin_t*0.6f, 0, default_code_color, pin_expr); + rd_code_label(pin_t*0.6f, 0, default_code_color, str8_lit("=")); + rd_code_label(pin_t*0.6f, 0, default_code_color, eval_string); } - UI_Signal pin_sig = ui_signal_from_box(pin_box); - if(ui_key_match(pin_box_key, ui_hot_key())) + if(ui_hovering(text_container_sig) && contains_2f32(pin_box->rect, ui_mouse())) { rd_set_hover_eval(v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), pin_expr); } @@ -2655,16 +2681,16 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); n->rng = txt_rng(*cursor, *mark); - n->color = ui_color_from_name(str8_lit("selection")); + n->color = ui_color_from_name(s("selection")); SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); } // rjf: push for ctrlified mouse expr - if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) UI_Tag(str8_lit("pop")) + if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) UI_Tag(s("pop")) { TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); n->rng = result.mouse_expr_rng; - n->color = ui_color_from_name(str8_lit("background")); + n->color = ui_color_from_name(s("background")); n->color.w *= 0.2f; SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); } @@ -2831,7 +2857,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_box_text_position(line_box).x+trail_off_span.max, line_box->rect.y1+params->font_size*0.125f, }; - Vec4F32 cursor_color = ui_color_from_name(str8_lit("cursor")); + Vec4F32 cursor_color = ui_color_from_name(s("cursor")); Vec4F32 trail_color = cursor_color; if(!is_focused) { @@ -3229,7 +3255,6 @@ rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, { RD_CodeColorSlot token_color_slot = rd_code_color_slot_from_txt_token_kind(token->kind); Vec4F32 token_color_rgba = rd_rgba_from_code_color_slot(token_color_slot); - token_color_rgba.w *= alpha; String8 token_string = str8_substr(string, token->range); if(str8_match(token_string, str8_lit("{"), 0)) { indirection_counter += 1; } if(str8_match(token_string, str8_lit("["), 0)) { indirection_counter += 1; } @@ -3238,6 +3263,7 @@ rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, { default: { + token_color_rgba.w *= alpha; DR_FStr fstr = { token_string, @@ -3265,6 +3291,7 @@ rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, F32 lookup_color_mix_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "%S_lookup", token_string), 1.f); token_color_rgba = mix_4f32(token_color_rgba, lookup_color, lookup_color_mix_t); } + token_color_rgba.w *= alpha; DR_FStr fstr = { token_string, @@ -3279,6 +3306,7 @@ rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, }break; case TXT_TokenKind_Numeric: { + token_color_rgba.w *= alpha; Vec4F32 token_color_rgba_alt = rd_rgba_from_code_color_slot(RD_CodeColorSlot_CodeNumericAltDigitGroup); token_color_rgba_alt.w *= alpha; F32 font_size = ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f));