diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index c40df17d..971a21f8 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -77,9 +77,10 @@ struct D_HandleArray typedef U32 D_BreakpointFlags; enum { - D_BreakpointFlag_BreakOnWrite = (1<<0), - D_BreakpointFlag_BreakOnRead = (1<<1), - D_BreakpointFlag_BreakOnExecute = (1<<2), + D_BreakpointFlag_BreakOnWrite = (1<<0), + D_BreakpointFlag_BreakOnRead = (1<<1), + D_BreakpointFlag_BreakOnExecute = (1<<2), + D_BreakpointFlag_BreakSelectedThreadOnly = (1<<3), }; typedef struct D_Breakpoint D_Breakpoint; diff --git a/src/dbg_engine/dbg_engine_ctrl.c b/src/dbg_engine/dbg_engine_ctrl.c index ba69ae65..2f7d3f66 100644 --- a/src/dbg_engine/dbg_engine_ctrl.c +++ b/src/dbg_engine/dbg_engine_ctrl.c @@ -5346,6 +5346,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) { Temp temp = temp_begin(scratch.arena); String8List conditions = {0}; + B32 filter_unselected_threads = 0; // rjf: entry breakpoints for(DMN_TrapChunkNode *n = entry_traps.first; n != 0; n = n->next) @@ -5383,6 +5384,10 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) { str8_list_push(temp.arena, &conditions, user_bp->condition); } + if(user_bp != 0 && !(trap->id & bit64) && user_bp->flags & D_BreakpointFlag_BreakSelectedThreadOnly) + { + filter_unselected_threads = 1; + } } } } @@ -5396,6 +5401,19 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg) hit_user_bp = 1; } + // rjf: if this breakpoint filters unselected threads, check that the current thread matches + // the selected, *or* that we have no selected thread at all. + if(!hit_conditional_bp_but_filtered && filter_unselected_threads) + { + B32 thread_is_selected = (d_handle_match(thread->handle, msg->entity) || d_handle_match(msg->entity, d_handle_zero())); + if(!thread_is_selected) + { + hit_user_bp = 0; + hit_conditional_bp_but_filtered = 1; + log_infof("thread_filtered_breakpoint_hit: 'not selected thread, and so filtered'\n"); + } + } + // rjf: evaluate hit stop conditions if(conditions.node_count != 0) ProfScope("evaluate hit stop conditions") { diff --git a/src/dbg_engine/dbg_engine_user.c b/src/dbg_engine/dbg_engine_user.c index 4ea507a3..038f1107 100644 --- a/src/dbg_engine/dbg_engine_user.c +++ b/src/dbg_engine/dbg_engine_user.c @@ -1569,7 +1569,7 @@ d_next_cmd(D_Cmd **cmd) //~ rjf: Main Layer Top-Level Calls internal D_EventList -d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info) +d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, D_Handle selected_thread, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -1683,6 +1683,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P // rjf: build data strings of all param data String8List strings = {0}; { + str8_list_push(scratch.arena, &strings, str8_struct(&selected_thread)); D_EntityArray threads = d_entity_array_from_kind(D_EntityKind_Thread); for EachIndex(idx, threads.count) { @@ -1696,6 +1697,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P for(U64 idx = 0; idx < breakpoints->count; idx += 1) { D_Breakpoint *bp = &breakpoints->v[idx]; + str8_list_push(scratch.arena, &strings, str8_struct(&bp->flags)); str8_list_push(scratch.arena, &strings, bp->file_path); str8_list_push(scratch.arena, &strings, str8_struct(&bp->pt)); str8_list_push(scratch.arena, &strings, bp->vaddr_expr); @@ -1994,7 +1996,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { need_run = 1; run_kind = d_user_state->ctrl_last_run_kind; - run_thread = d_entity_from_handle(d_user_state->ctrl_last_run_thread_handle); + run_thread = d_entity_from_handle(selected_thread); run_flags = d_user_state->ctrl_last_run_flags; run_traps = d_user_state->ctrl_last_run_traps; }break; @@ -2030,6 +2032,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { run_extra_bps.v[0].vaddr_expr = push_str8f(scratch.arena, "0x%I64x", params->vaddr); } + run_extra_bps.v[0].flags |= D_BreakpointFlag_BreakSelectedThreadOnly; d_cmd(D_CmdKind_Run); }break; case D_CmdKind_RunToName: @@ -2130,7 +2133,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { need_run = 1; run_kind = d_user_state->ctrl_last_run_kind; - run_thread = d_entity_from_handle(d_user_state->ctrl_last_run_thread_handle); + run_thread = d_entity_from_handle(selected_thread); run_flags = d_user_state->ctrl_last_run_flags; run_traps = d_user_state->ctrl_last_run_traps; } @@ -2252,7 +2255,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P arena_clear(d_user_state->ctrl_last_run_arena); d_user_state->ctrl_last_run_kind = run_kind; d_user_state->ctrl_last_run_frame_idx = d_frame_index(); - d_user_state->ctrl_last_run_thread_handle = run_thread->handle; d_user_state->ctrl_last_run_flags = run_flags; d_user_state->ctrl_last_run_traps = d_trap_list_copy(d_user_state->ctrl_last_run_arena, &run_traps_copy); d_user_state->ctrl_last_run_extra_bps = d_breakpoint_array_copy(d_user_state->ctrl_last_run_arena, &run_extra_bps_copy); diff --git a/src/dbg_engine/dbg_engine_user.h b/src/dbg_engine/dbg_engine_user.h index ba467329..7cf59551 100644 --- a/src/dbg_engine/dbg_engine_user.h +++ b/src/dbg_engine/dbg_engine_user.h @@ -366,7 +366,6 @@ struct D_UserState Arena *ctrl_last_run_arena; D_RunKind ctrl_last_run_kind; U64 ctrl_last_run_frame_idx; - D_Handle ctrl_last_run_thread_handle; D_RunFlags ctrl_last_run_flags; D_TrapList ctrl_last_run_traps; D_BreakpointArray ctrl_last_run_extra_bps; @@ -481,6 +480,6 @@ internal B32 d_next_cmd(D_Cmd **cmd); //////////////////////////////// //~ rjf: Main Layer Top-Level Calls -internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info); +internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, D_Handle selected_thread, U64 exception_code_filters[(D_ExceptionCodeKind_COUNT+63)/64], B32 auto_download_debug_info); #endif // DBG_ENGINE_USER_H diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 52ab0f05..7a9d7690 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -438,7 +438,7 @@ RD_VocabInfo rd_vocab_info_table[370] = 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('Use Alternative Font For UI') @description(\"Uses an alternative font for non-code UI elements.\")\n @default(1) 'use_alternative_font_for_ui': bool,\n @expand_if(\"$.use_alternative_font_for_ui\") @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 @expand_if(\"$.use_alternative_font_for_ui\") @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n @expand_if(\"!$.use_alternative_font_for_ui\") @display_name('Font') @description(\"The name of, or path to, the font used in all UI.\")\n @default('') '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') @expand_if(\"$.animations\") @description(\"Controls whether or not a movement trail animation 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 //- rjf: auto-load last project\n @default(0) @display_name('Auto Load Last Project') @description(\"Enables loading the most recently opened project, if one is not specified from the command line.\")\n 'auto_load_last_project': bool,\n\n //- rjf: symbol server\n @default(0) @display_name('Auto Download Debug Info') @description(\"Automatically tries to download missing debug info from symbol server(s).\")\n 'auto_download_debug_info': bool,\n\n //- rjf: update check\n @default(1) @display_name('Check For Updates') @description(\"Enables a small network request to check if there is a newer release version available.\")\n 'check_for_updates': bool,\n\n //- rjf: system installation\n @display_name('Install To System') @description(\"Controls whether or not associated installation files are created on the system, for tighter integration with the operating system shell.\") 'install_to_system': 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('Use Alternative Font For UI') @description(\"Uses an alternative font for non-code UI elements.\")\n @default(1) 'use_alternative_font_for_ui': bool,\n @expand_if(\"$.use_alternative_font_for_ui\") @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 @expand_if(\"$.use_alternative_font_for_ui\") @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n @expand_if(\"!$.use_alternative_font_for_ui\") @display_name('Font') @description(\"The name of, or path to, the font used in all UI.\")\n @default('') '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') @expand_if(\"$.animations\") @description(\"Controls whether or not a movement trail animation 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 //- rjf: auto-load last project\n @default(0) @display_name('Auto Load Last Project') @description(\"Enables loading the most recently opened project, if one is not specified from the command line.\")\n 'auto_load_last_project': bool,\n\n //- rjf: symbol server\n @default(0) @display_name('Auto Download Debug Info') @description(\"Automatically tries to download missing debug info from symbol server(s).\")\n 'auto_download_debug_info': bool,\n\n //- rjf: breakpoint behavior\n @default(0) @display_name('Lock New Breakpoints To Selected Thread') @description(\"When placing breakpoints, locks them to the selected thread by default.\")\n 'lock_new_breakpoints_to_selected_thread': bool,\n\n //- rjf: update check\n @default(1) @display_name('Check For Updates') @description(\"Enables a small network request to check if there is a newer release version available.\")\n 'check_for_updates': bool,\n\n //- rjf: system installation\n @display_name('Install To System') @description(\"Controls whether or not associated installation files are created on the system, for tighter integration with the operating system shell.\") 'install_to_system': 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")}, @@ -467,7 +467,7 @@ RD_NameSchemaInfo rd_name_schema_info_table[39] = {str8_lit_comp("geo3d"), 1, str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Expression\") @description(\"An expression to describe the base address of the index buffer.\")\n 'expression': expr_string,\n 'count': expr_string,\n 'vtx': expr_string,\n 'vtx_size': expr_string,\n 'yaw': @range[0, 1] f32,\n 'pitch': @range[-0.5, 0] f32,\n 'zoom': @range[0, 100] f32,\n}\n")}, {str8_lit_comp("getting_started"), 0, str8_lit_comp("@inherit(tab) x:\n{\n}\n")}, {str8_lit_comp("target"), 0, str8_lit_comp("@row_commands(@cmd_line save_cfg_to_project, enable_cfg, launch_and_run, launch_and_step_into, duplicate_cfg, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': @folder path,\n 'entry_point': expr_string,\n @default(\"output\") 'output_label': code_string,\n 'stdout_path': @can_not_exist @no_relativize path,\n 'stderr_path': @can_not_exist @no_relativize path,\n 'stdin_path': @can_not_exist @no_relativize path,\n 'environment': set,\n 'debug_subprocesses': bool,\n @no_revert @no_expand @default(0) 'enabled': bool,\n}\n")}, -{str8_lit_comp("breakpoint"), 0, str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint, clear_breakpoints)\nx:\n{\n 'label': code_string,\n 'condition': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n 'hit_count': u64,\n 'address_range_size': @or(0, 1, 2, 4, 8) u64,\n 'break_on_write': bool,\n 'break_on_read': bool,\n 'break_on_execute': bool,\n @no_revert @no_expand @default(1) 'enabled': bool,\n}\n")}, +{str8_lit_comp("breakpoint"), 0, str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint, clear_breakpoints)\nx:\n{\n 'label': code_string,\n 'condition': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n 'hit_count': u64,\n 'address_range_size': @or(0, 1, 2, 4, 8) u64,\n 'break_on_write': bool,\n 'break_on_read': bool,\n 'break_on_execute': bool,\n @display_name(\"Break Selected Thread Only\") 'break_selected_thread_only': bool,\n @no_revert @no_expand @default(1) 'enabled': bool,\n}\n")}, {str8_lit_comp("watch_pin"), 0, str8_lit_comp("@row_commands(duplicate_cfg, remove_cfg)\n@collection_commands(add_watch_pin, toggle_watch_pin)\nx:\n{\n 'expression': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n}\n")}, {str8_lit_comp("debug_info"), 0, str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(load_debug_info)\nx:\n{\n 'path': @no_relativize path,\n @no_revert @no_expand @default(1) 'enabled': bool,\n @query 'guid': string,\n}\n")}, {str8_lit_comp("file_path_map"), 0, str8_lit_comp("@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @no_relativize path, 'dest': @no_relativize path}")}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index a1ec9285..2c9d75a8 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -326,6 +326,10 @@ RD_VocabTable: @default(0) @display_name('Auto Download Debug Info') @description("Automatically tries to download missing debug info from symbol server(s).") 'auto_download_debug_info': bool, + //- rjf: breakpoint behavior + @default(0) @display_name('Lock New Breakpoints To Selected Thread') @description("When placing breakpoints, locks them to the selected thread by default.") + 'lock_new_breakpoints_to_selected_thread': bool, + //- rjf: update check @default(1) @display_name('Check For Updates') @description("Enables a small network request to check if there is a newer release version available.") 'check_for_updates': bool, @@ -756,6 +760,7 @@ RD_VocabTable: 'break_on_write': bool, 'break_on_read': bool, 'break_on_execute': bool, + @display_name("Break Selected Thread Only") 'break_selected_thread_only': bool, @no_revert @no_expand @default(1) 'enabled': bool, } ```, diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 02feb823..ca3898bc 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -16864,6 +16864,11 @@ rd_frame(void) rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x", bp->id), .do_lister = 0); } str8_list_pushf(rd_state->cmd_output_arena, &rd_state->cmd_outputs, "$%I64x", bp->id); + if(rd_setting_b32_from_name(s("lock_new_breakpoints_to_selected_thread"))) + { + CFG_Node *filter = cfg_node_new(rd_state->cfg, bp, s("break_selected_thread_only")); + cfg_node_new(rd_state->cfg, filter, s("1")); + } } } }break; @@ -17997,18 +18002,22 @@ rd_frame(void) //- rjf: compute breakpoint flags D_BreakpointFlags flags = 0; - if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_write"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, s("break_on_write"))->first->string, s("1"), 0)) { flags |= D_BreakpointFlag_BreakOnWrite; } - if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_read"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, s("break_on_read"))->first->string, s("1"), 0)) { flags |= D_BreakpointFlag_BreakOnRead; } - if(str8_match(cfg_node_child_from_string(src_bp, str8_lit("break_on_execute"))->first->string, str8_lit("1"), 0)) + if(str8_match(cfg_node_child_from_string(src_bp, s("break_on_execute"))->first->string, s("1"), 0)) { flags |= D_BreakpointFlag_BreakOnExecute; } + if(str8_match(cfg_node_child_from_string(src_bp, s("break_selected_thread_only"))->first->string, s("1"), 0)) + { + flags |= D_BreakpointFlag_BreakSelectedThreadOnly; + } //- rjf: compute address range size U64 addr_range_size = 0; @@ -18073,7 +18082,7 @@ rd_frame(void) } U64 cmd_count_pre_tick = rd_state->cmds[0].count; B32 soft_halt_issued = d_user_state->ctrl_soft_halt_issued; - D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, exception_code_filters, rd_state->auto_download_debug_info); + D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, rd_base_regs()->thread, exception_code_filters, rd_state->auto_download_debug_info); //////////////////////////// //- rjf: process debug engine events diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index c9810b4c..ffe9a842 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -1225,6 +1225,7 @@ struct RD_BreakpointBoxDrawExtData B32 do_glow; B32 is_disabled; B32 is_conditioned; + B32 is_global; }; internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions) @@ -1308,6 +1309,20 @@ internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions) scratch_end(scratch); } + // rjf: draw non-global marker + if(!u->is_global) UI_TagF(u->is_disabled ? "weak" : "") + { + Temp scratch = scratch_begin(0, 0); + Vec4F32 color = ui_color_from_name(s("text")); + FNT_Run run = fnt_run_from_string(rd_font_from_slot(RD_FontSlot_Icons), box->font_size*0.85f, 0, 0, FNT_RasterFlag_Smooth, rd_icon_kind_text_table[RD_IconKind_Thread]); + Vec2F32 box_dim = dim_2f32(box->rect); + Vec2F32 p = center_2f32(box->rect); + p.x += box_dim.x*0.1f; + p.y += box_dim.y*0.4f; + dr_text_run(p, color, run); + scratch_end(scratch); + } + // rjf: draw disabled marker if(u->is_disabled) { @@ -1801,6 +1816,7 @@ rd_code_slice(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred { bp_rgba = v4f32(bp_rgba.x*0.45f, bp_rgba.y*0.45f, bp_rgba.z*0.45f, bp_rgba.w*0.45f); } + B32 bp_is_global = !str8_match(cfg_node_child_from_string(bp, s("break_selected_thread_only"))->first->string, s("1"), 0); // rjf: prep custom rendering data RD_BreakpointBoxDrawExtData *bp_draw = push_array(ui_build_arena(), RD_BreakpointBoxDrawExtData, 1); @@ -1814,6 +1830,7 @@ rd_code_slice(RD_CodeSliceParams *params, U64 *cursor, U64 *mark, S64 *preferred bp_draw->do_glow = do_bp_glow; bp_draw->is_disabled = bp_is_disabled; bp_draw->is_conditioned = (cfg_node_child_from_string(bp, s("condition"))->first->string.size != 0); + bp_draw->is_global = bp_is_global; if(params->line_vaddrs[line_idx] == 0) { D_LineList *lines = ¶ms->line_infos[line_idx];