From fe270d4d485d6f998734e93183c798c0be2fd043 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Wed, 23 Nov 2022 15:23:25 +0900 Subject: [PATCH 001/263] Make sure to wait TCP/IP server to start up Currently, the test on TCP/IP mode sometimes fails because the debugger fails to connect to debuggee. See https://github.com/ruby/debug/actions/runs/3527685026/jobs/5917010231#step:4:338 FYI: The reason why the test has not failed until now is the test framework did not correctly detect that debuggee was terminated. Since the test framework correctly detected it from ruby/debug@6d9f231, the test began to fail, as it did this time. --- test/support/test_case.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index e5e0dd9e4..08787586c 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -187,6 +187,9 @@ def setup_unix_domain_socket_remote_debuggee def setup_tcpip_remote_debuggee remote_info = setup_remote_debuggee("#{RDBG_EXECUTABLE} -O --port=#{TCPIP_PORT} -- #{temp_file_path}") remote_info.port = TCPIP_PORT + Timeout.timeout(TIMEOUT_SEC) do + sleep 0.001 until remote_info.debuggee_backlog.join.include? remote_info.port.to_s + end remote_info end From 3e3f374e905a45b6a1bc020d64a40688fa702719 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 24 Nov 2022 18:28:49 +0900 Subject: [PATCH 002/263] revert #746 fix #799 --- ext/debug/debug.c | 29 ----------------------------- ext/debug/extconf.rb | 8 -------- 2 files changed, 37 deletions(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index fc4b4bb5a..81c960541 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -89,34 +89,6 @@ capture_frames(VALUE self, VALUE skip_path_prefix) return rb_debug_inspector_open(di_body, (void *)skip_path_prefix); } -#ifdef RB_PROFILE_FRAMES_HAS_C_FRAMES -#define BUFF_SIZE 4096 - -static VALUE -frame_depth(VALUE self) -{ - static VALUE buff[BUFF_SIZE]; - static int lines[BUFF_SIZE]; - - int size = rb_profile_frames(0, BUFF_SIZE, buff, lines); - - // If the buffer is full, there might be more frames. - // Fall back to rb_make_backtrace to get them all. - if (size >= BUFF_SIZE) { - VALUE bt = rb_make_backtrace(); - size = RARRAY_LEN(bt); - return INT2FIX(size); - } - - // rb_profile_frames will return one extra frame - // https://bugs.ruby-lang.org/issues/18907 - #ifdef RB_PROFILE_FRAMES_HAS_EXTRA_FRAME - return INT2FIX(size - 1); - #else - return INT2FIX(size); - #endif -} -#else static VALUE frame_depth(VALUE self) { @@ -124,7 +96,6 @@ frame_depth(VALUE self) VALUE bt = rb_make_backtrace(); return INT2FIX(RARRAY_LEN(bt)); } -#endif // iseq diff --git a/ext/debug/extconf.rb b/ext/debug/extconf.rb index c9d056b7e..b4e78fbe3 100644 --- a/ext/debug/extconf.rb +++ b/ext/debug/extconf.rb @@ -7,14 +7,6 @@ $defs << '-DHAVE_RB_ISEQ_PARAMETERS' $defs << '-DHAVE_RB_ISEQ_CODE_LOCATION' - if RUBY_VERSION >= '3.0.0' - $defs << '-DRB_PROFILE_FRAMES_HAS_C_FRAMES' - - if RUBY_VERSION < '3.2.0' - $defs << '-DRB_PROFILE_FRAMES_HAS_EXTRA_FRAME' - end - end - if RUBY_VERSION >= '3.1.0' $defs << '-DHAVE_RB_ISEQ_TYPE' end From 3f4cae4cef185c13342ef2f945c84ef38d3fe322 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 12:10:16 +0900 Subject: [PATCH 003/263] use `rb_debug_inspector_frame_depth` Use `rb_debug_inspector_frame_depth()` from Ruby 3.2. --- ext/debug/debug.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index 81c960541..9eaac2bbd 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -76,7 +76,12 @@ di_body(const rb_debug_inspector_t *dc, void *ptr) rb_debug_inspector_frame_binding_get(dc, i), iseq, rb_debug_inspector_frame_class_get(dc, i), - INT2FIX(len - i)); +#ifdef RB_DEBUG_INSPECTOR_FRAME_DEPTH + rb_debug_inspector_frame_depth(dc, i) +#else + INT2FIX(len - i) +#endif + ); rb_ary_push(ary, e); } @@ -89,6 +94,13 @@ capture_frames(VALUE self, VALUE skip_path_prefix) return rb_debug_inspector_open(di_body, (void *)skip_path_prefix); } +#ifdef RB_DEBUG_INSPECTOR_FRAME_DEPTH +static VALUE +frame_depth(VALUE self) +{ + return rb_debug_inspector_current_depth(); +} +#else static VALUE frame_depth(VALUE self) { @@ -96,6 +108,8 @@ frame_depth(VALUE self) VALUE bt = rb_make_backtrace(); return INT2FIX(RARRAY_LEN(bt)); } +#endif + // iseq From f9477c33aa1c251bb92c5e4cac22d114877d497c Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 14:48:13 +0900 Subject: [PATCH 004/263] modify test target script --- test/console/control_flow_commands_test.rb | 109 +++++++++++---------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/test/console/control_flow_commands_test.rb b/test/console/control_flow_commands_test.rb index 0ac6ee521..c6dcea3c7 100644 --- a/test/console/control_flow_commands_test.rb +++ b/test/console/control_flow_commands_test.rb @@ -10,114 +10,117 @@ class BasicControlFlowTest < ConsoleTestCase def program <<~RUBY 1| class Student - 2| def initialize(name) - 3| @name = name + 2| def initialize(name, age) + 3| @name = name; @age = age 4| end 5| 6| def name 7| @name 8| end - 9| end - 10| - 11| s = Student.new("John") - 12| s.name - 13| "foo" + 9| + 10| def age + 11| @age + 12| end + 13| end + 14| + 15| s = Student.new("John", 17) + 16| s.name; s.age + 17| s.inspect # do not show RUBY end def test_step_goes_to_the_next_statement - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 + assert_line_num 15 type 's' assert_line_num 3 type 's' assert_line_num 4 type 's' - assert_line_num 12 + assert_line_num 16 type 's' assert_line_num 7 type 's' assert_line_num 8 type 's' - assert_line_num 13 - type 'quit' - type 'y' + assert_line_num 11 + type 's' + assert_line_num 12 + type 's' + assert_line_num 17 + type 's' end end def test_step_with_number_goes_to_the_next_nth_statement - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 + assert_line_num 15 type 's 2' assert_line_num 4 type 's 3' assert_line_num 8 - type 's' - assert_line_num 13 - type 'quit' - type 'y' + type 's 2' + assert_line_num 12 + type 's 2' end end def test_next_goes_to_the_next_line - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 + assert_line_num 15 type 'n' - assert_line_num 12 + assert_line_num 16 + type 'n' + assert_line_num 17 type 'n' - assert_line_num 13 - type 'quit' - type 'y' end end def test_next_with_number_goes_to_the_next_nth_line - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 + assert_line_num 15 type 'n 2' - assert_line_num 13 - type 'quit' - type 'y' + assert_line_num 17 + type 'n' end end def test_continue_goes_to_the_next_breakpoint - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 - type 'b 13' + assert_line_num 15 + type 'b 17' + type 'c' + assert_line_num 17 type 'c' - assert_line_num 13 - type 'quit' - type 'y' end end def test_finish_leaves_the_current_frame - debug_code(program) do - type 'b 11' + debug_code program do + type 'b 15' type 'c' - assert_line_num 11 + assert_line_num 15 type 's' assert_line_num 3 type 'fin' assert_line_num 4 type 's' - assert_line_num 12 + assert_line_num 16 type 's' assert_line_num 7 type 'fin' assert_line_num 8 - type 'kill!' + type 'c' end end end @@ -136,7 +139,7 @@ def program end def test_step_steps_out_of_blocks_when_done - debug_code(program) do + debug_code program do type 'step' assert_line_num 2 type 'step' @@ -153,7 +156,7 @@ def test_step_steps_out_of_blocks_when_done end def test_next_steps_out_of_blocks_right_away - debug_code(program) do + debug_code program do type 'step' assert_line_num 2 type 'next' @@ -309,7 +312,7 @@ def program end def test_next_steps_out_of_if_blocks_when_done - debug_code(program) do + debug_code program do type 'next' assert_line_num 6 type 'quit' @@ -318,7 +321,7 @@ def test_next_steps_out_of_if_blocks_when_done end def test_step_steps_out_of_if_blocks_when_done - debug_code(program) do + debug_code program do type 'step' assert_line_num 6 type 'quit' @@ -347,7 +350,7 @@ def program end def test_next_steps_over_rescue_when_raising_from_method - debug_code(program) do + debug_code program do type 'break Foo::Bar.raise_error' type 'continue' assert_line_num 4 @@ -479,7 +482,7 @@ def program end def test_next - debug_code(program) do + debug_code program do type 'b 13' type 'c' assert_line_num 13 @@ -490,7 +493,7 @@ def test_next end def test_finish - debug_code(program) do + debug_code program do type 'b 13' type 'c' assert_line_num 13 From 6baa2ecd4e5cb943413305daac7273f6fc5780be Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 15:46:24 +0900 Subject: [PATCH 005/263] fix next/finish/until for duplicate lines On the code like that: ```ruby foo; bar next_line ``` and breaking at the end of `foo`, `next` command moves to the beggining of `bar`, bit it should be `next_line`. This patch solves this issue. --- lib/debug/thread_client.rb | 55 ++++++++++++++-------- test/console/control_flow_commands_test.rb | 49 +++++++++++++++++-- 2 files changed, 79 insertions(+), 25 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 1379352f2..5cce77a06 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -870,6 +870,7 @@ def wait_next_action_ frame = @target_frames.first path = frame.location.absolute_path || "!eval:#{frame.path}" line = frame.location.lineno + label = frame.location.base_label if frame.iseq frame.iseq.traceable_lines_norec(lines = {}) @@ -881,23 +882,32 @@ def wait_next_action_ depth = @target_frames.first.frame_depth - step_tp iter do + step_tp iter do |tp| loc = caller_locations(2, 1).first loc_path = loc.absolute_path || "!eval:#{loc.path}" + loc_label = loc.base_label + loc_depth = DEBUGGER__.frame_depth - 3 - # same stack depth - (DEBUGGER__.frame_depth - 3 <= depth) || - - # different frame - (next_line && loc_path == path && - (loc_lineno = loc.lineno) > line && - loc_lineno <= next_line) + case + when loc_depth == depth && loc_label == label + true + when loc_depth < depth + # lower stack depth + true + when (next_line && + loc_path == path && + (loc_lineno = loc.lineno) > line && + loc_lineno <= next_line) + # different frame (maybe block) but the line is before next_line + true + end end break when :finish finish_frames = (iter || 1) - 1 - goal_depth = @target_frames.first.frame_depth - finish_frames + frame = @target_frames.first + goal_depth = frame.frame_depth - finish_frames - (frame.has_return_value ? 1 : 0) step_tp nil, [:return, :b_return] do DEBUGGER__.frame_depth - 3 <= goal_depth ? true : false @@ -907,22 +917,25 @@ def wait_next_action_ when :until location = iter&.strip frame = @target_frames.first - depth = frame.frame_depth + depth = frame.frame_depth - (frame.has_return_value ? 1 : 0) target_location_label = frame.location.base_label case location when nil, /\A(?:(.+):)?(\d+)\z/ - file = $1 + no_loc = !location + file = $1 || frame.location.path line = ($2 || frame.location.lineno + 1).to_i step_tp nil, [:line, :return] do |tp| if tp.event == :line - next true if file && tp.path.end_with?(file) - next true if tp.lineno >= line + next false if no_loc && depth < DEBUGGER__.frame_depth - 3 + next false unless tp.path.end_with?(file) + next false unless tp.lineno >= line + true else - next true if depth >= DEBUGGER__.frame_depth - 3 && - caller_locations(2, 1).first.label == target_location_label - # TODO: imcomplete condition + true if depth >= DEBUGGER__.frame_depth - 3 && + caller_locations(2, 1).first.label == target_location_label + # TODO: imcomplete condition end end else @@ -934,11 +947,11 @@ def wait_next_action_ step_tp nil, [:call, :c_call, :return] do |tp| case tp.event when :call, :c_call - next true if pat === tp.callee_id.to_s + true if pat === tp.callee_id.to_s else # :return, :b_return - next true if depth >= DEBUGGER__.frame_depth - 3 && - caller_locations(2, 1).first.label == target_location_label - # TODO: imcomplete condition + true if depth >= DEBUGGER__.frame_depth - 3 && + caller_locations(2, 1).first.label == target_location_label + # TODO: imcomplete condition end end end @@ -1181,6 +1194,8 @@ def wait_next_action_ rescue Exception => e pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace] raise + ensure + @returning = false end def debug_event(ev, args) diff --git a/test/console/control_flow_commands_test.rb b/test/console/control_flow_commands_test.rb index c6dcea3c7..dd46301b8 100644 --- a/test/console/control_flow_commands_test.rb +++ b/test/console/control_flow_commands_test.rb @@ -82,6 +82,19 @@ def test_next_goes_to_the_next_line end end + def test_next_skips_method_in_a_same_line + debug_code program do + type 'b 7' + type 'c' + assert_line_num 7 + type 'n' + assert_line_num 8 + type 'n' + assert_line_num 17 + type 'n' + end + end + def test_next_with_number_goes_to_the_next_nth_line debug_code program do type 'b 15' @@ -123,6 +136,17 @@ def test_finish_leaves_the_current_frame type 'c' end end + + def test_finish_skips_method_in_a_same_line + debug_code program do + type 'b 7' + type 'c' + assert_line_num 7 + type 'fin' + assert_line_num 8 + type 'fin' + end + end end # @@ -254,7 +278,6 @@ def test_finish_4 end end - def program2 <<~RUBY 1| def foo x @@ -279,7 +302,7 @@ def test_finish_param type 'finish' assert_line_num 6 type 'next' - assert_line_num 2 + assert_line_num 9 type 'c' end end @@ -417,9 +440,13 @@ def program 4| end 5| c = 3 6| def foo - 7| x = 1 + 7| @x = 1 8| end - 9| foo + 9| def bar + 10| @y = 2 + 11| end + 12| foo; bar + 13| [@x, @y].inspect RUBY end @@ -447,11 +474,23 @@ def test_until_method debug_code program do type 'u foo' assert_line_num 7 - type 'u bar' + type 'u baz' assert_line_num 8 type 'c' end end + + def test_unit_method_in_the_same_line + debug_code program do + type 'u foo' + assert_line_num 7 + type 'u' + assert_line_num 8 + type 'u' + assert_line_num 13 + type 'c' + end + end end # From 2a73341fca572b137dea4c4c9c5c34e91cc1c89d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 17:33:06 +0900 Subject: [PATCH 006/263] add `cont` alias for `continue` --- lib/debug/session.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index b83479390..dccdf216c 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -487,9 +487,9 @@ def register_default_command step_command :until, arg end - # * `c[ontinue]` + # * `c` or `cont` or `continue` # * Resume the program. - register_command 'c', 'continue', + register_command 'c', 'cont', 'continue', repeat: true, cancel_auto_continue: true do |arg| leave_subsession :continue From e50616196bb0dfc6aea46db0e2969ab1f9a1f2e1 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 17:27:11 +0900 Subject: [PATCH 007/263] rename file name `debugger` is not a statement but a method. --- ...tement_test.rb => debugger_method_test.rb} | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) rename test/console/{debug_statement_test.rb => debugger_method_test.rb} (75%) diff --git a/test/console/debug_statement_test.rb b/test/console/debugger_method_test.rb similarity index 75% rename from test/console/debug_statement_test.rb rename to test/console/debugger_method_test.rb index 54fe466f3..709cfb80e 100644 --- a/test/console/debug_statement_test.rb +++ b/test/console/debugger_method_test.rb @@ -3,23 +3,23 @@ require_relative '../support/console_test_case' module DEBUGGER__ - class DebugStatementTest < ConsoleTestCase - STATEMENT_PLACE_HOLDER = "__BREAK_STATEMENT__" - SUPPORTED_DEBUG_STATEMENTS = %w(binding.break binding.b debugger).freeze + class DebuggerMethodTest < ConsoleTestCase + METHOD_PLACE_HOLDER = "__BREAK_METHOD__" + SUPPORTED_DEBUG_METHODS = %w(debugger binding.break binding.b).freeze def debug_code(program) - SUPPORTED_DEBUG_STATEMENTS.each do |statement| - super(program.gsub(STATEMENT_PLACE_HOLDER, statement)) + SUPPORTED_DEBUG_METHODS.each do |mid| + super(program.gsub(METHOD_PLACE_HOLDER, mid)) end end end - class BasicTest < DebugStatementTest + class DebuggerMethodBasicTest < DebuggerMethodTest def program <<~RUBY 1| class Foo 2| def bar - 3| #{STATEMENT_PLACE_HOLDER} + 3| #{METHOD_PLACE_HOLDER} 4| end 5| end 6| @@ -36,17 +36,17 @@ def test_breakpoint_fires_correctly end end - class DebugStatementWithPreCommandTest < DebugStatementTest + class DebuggerMethodWithPreCommandTest < DebuggerMethodTest def program <<~RUBY 1| class Foo 2| def bar - 3| #{STATEMENT_PLACE_HOLDER}(pre: "p 'aaaaa'") + 3| #{METHOD_PLACE_HOLDER}(pre: "p 'aaaaa'") 4| baz 5| end 6| 7| def baz - 8| #{STATEMENT_PLACE_HOLDER} + 8| #{METHOD_PLACE_HOLDER} 9| end 10| end 11| @@ -77,17 +77,17 @@ def test_debugger_doesnt_complain_about_duplicated_breakpoint end end - class DebugStatementWithDoCommandTest < DebugStatementTest + class DebuggerMethodWithDoCommandTest < DebuggerMethodTest def program <<~RUBY 1| class Foo 2| def bar - 3| #{STATEMENT_PLACE_HOLDER}(do: "p 'aaaaa'") + 3| #{METHOD_PLACE_HOLDER}(do: "p 'aaaaa'") 4| baz 5| end 6| 7| def baz - 8| #{STATEMENT_PLACE_HOLDER} + 8| #{METHOD_PLACE_HOLDER} 9| end 10| end 11| @@ -113,18 +113,18 @@ def test_debugger_doesnt_complain_about_duplicated_breakpoint end end - class ThreadManagementTest < DebugStatementTest + class ThreadManagementTest < DebuggerMethodTest def program <<~RUBY 1| Thread.new do - 2| #{STATEMENT_PLACE_HOLDER}(do: "p 'foo' + 'bar'") + 2| #{METHOD_PLACE_HOLDER}(do: "p 'foo' + 'bar'") 3| end.join 4| 5| Thread.new do - 6| #{STATEMENT_PLACE_HOLDER}(do: "p 'bar' + 'baz'") + 6| #{METHOD_PLACE_HOLDER}(do: "p 'bar' + 'baz'") 7| end.join 8| - 9| #{STATEMENT_PLACE_HOLDER} + 9| #{METHOD_PLACE_HOLDER} RUBY end From 5bb2ff149d0247bc92ac89651f29c2c2054fdb5a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 17:27:53 +0900 Subject: [PATCH 008/263] support `debugger` method in subsession supports `debugger do: "command"` in subsession. --- lib/debug/session.rb | 11 +++++++++-- test/console/debugger_method_test.rb | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index dccdf216c..f6dfb3b90 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2492,10 +2492,17 @@ def debugger pre: nil, do: nil, up_level: 0 return if !defined?(::DEBUGGER__::SESSION) || !::DEBUGGER__::SESSION.active? if pre || (do_expr = binding.local_variable_get(:do)) - cmds = ['binding.break', pre, do_expr] + cmds = ['#debugger', pre, do_expr] end - loc = caller_locations(up_level, 1).first; ::DEBUGGER__.add_line_breakpoint loc.path, loc.lineno + 1, oneshot: true, command: cmds + if ::DEBUGGER__::SESSION.in_subsession? + if cmds + commands = [*cmds[1], *cmds[2]].map{|c| c.split(';;').join("\n")} + ::DEBUGGER__::SESSION.add_preset_commands cmds[0], commands, kick: false, continue: false + end + else + loc = caller_locations(up_level, 1).first; ::DEBUGGER__.add_line_breakpoint loc.path, loc.lineno + 1, oneshot: true, command: cmds + end self end diff --git a/test/console/debugger_method_test.rb b/test/console/debugger_method_test.rb index 709cfb80e..8cc32198f 100644 --- a/test/console/debugger_method_test.rb +++ b/test/console/debugger_method_test.rb @@ -34,6 +34,20 @@ def test_breakpoint_fires_correctly type 'kill!' end end + + def test_debugger_method_in_subsession + debug_code program do + type 'c' + assert_line_num 3 + type 'eval debugger do: "p 2 ** 32"' + assert_line_text('4294967296') + type 'eval debugger do: "p 2 ** 32;; n;; p 2 ** 33;;"' + assert_line_num 4 + assert_line_text('4294967296') + assert_line_text('8589934592') + type 'c' + end + end end class DebuggerMethodWithPreCommandTest < DebuggerMethodTest From 182e779b1ec5cc47d9fd5bdb790b25f7e0145ea6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 25 Nov 2022 18:30:49 +0900 Subject: [PATCH 009/263] DAP: support to show global variables --- lib/debug/server_dap.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 18eccdd55..a0217f3c5 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -540,8 +540,8 @@ def process_protocol_request req if ref = @var_map[varid] case ref[0] when :globals - vars = global_variables.map do |name| - gv = 'Not implemented yet...' + vars = global_variables.sort.map do |name| + gv = eval(name.to_s) { name: name, value: gv.inspect, From 2f40ad4fee3e8a8c9161d5677033fbc8db00a4cb Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 25 Nov 2022 21:23:58 +0900 Subject: [PATCH 010/263] CDP: support to show global variables --- lib/debug/server_cdp.rb | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index a63dbb2b9..729e7de52 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -685,6 +685,28 @@ def puts result end class Session + # FIXME: unify this method with ThreadClient#propertyDescriptor. + def get_type obj + case obj + when Array + ['object', 'array'] + when Hash + ['object', 'map'] + when String + ['string'] + when TrueClass, FalseClass + ['boolean'] + when Symbol + ['symbol'] + when Integer, Float + ['number'] + when Exception + ['object', 'error'] + else + ['object'] + end + end + def fail_response req, **result @ui.respond_fail req, **result return :retry @@ -716,9 +738,28 @@ def process_protocol_request req frame_id = ref[1] fid = @frame_map[frame_id] request_tc [:cdp, :scope, req, fid] + when 'global' + vars = global_variables.sort.map do |name| + gv = eval(name.to_s) + prop = { + name: name, + value: { + description: gv.inspect + }, + configurable: true, + enumerable: true + } + type, subtype = get_type(gv) + prop[:value][:type] = type + prop[:value][:subtype] = subtype if subtype + prop + end + + @ui.respond req, result: vars + return :retry when 'properties' request_tc [:cdp, :properties, req, oid] - when 'script', 'global' + when 'script' # TODO: Support script and global types @ui.respond req, result: [] return :retry From 64dae96b470fb69a8301c463029331328e89a49a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 26 Nov 2022 04:33:55 +0900 Subject: [PATCH 011/263] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ca1f7a1a..a1218bad6 100644 --- a/README.md +++ b/README.md @@ -566,7 +566,7 @@ The `<...>` notation means the argument. * Run til the program reaches given location or the end of the current frame. * `u[ntil] * Run til the program invokes a method ``. `` can be a regexp with `/name/`. -* `c[ontinue]` +* `c` or `cont` or `continue` * Resume the program. * `q[uit]` or `Ctrl-D` * Finish debugger (with the debuggee process on non-remote debugging). From 6def10a9cc88debfe1529b5a423c05813a9c7d10 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 26 Nov 2022 04:34:36 +0900 Subject: [PATCH 012/263] fix break line check algorithm If specify the break line on the method definition, it stops at the beggining of method at called time (don't stop at method definition timing). The line check algorithm has a bug and this patch fix it. --- lib/debug/breakpoint.rb | 11 ++--- test/console/break_test.rb | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/lib/debug/breakpoint.rb b/lib/debug/breakpoint.rb index e288a4555..65161f919 100644 --- a/lib/debug/breakpoint.rb +++ b/lib/debug/breakpoint.rb @@ -273,13 +273,10 @@ def try_activate root_iseq = nil if !nearest || ((line - nline).abs < (line - nearest.line).abs) nearest = NearestISeq.new(iseq, nline, events) - else - if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno - if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) || - (events.include?(:RUBY_EVENT_CALL)) - nearest = NearestISeq.new(iseq, nline, events) - end - end + elsif @hook_call && + nearest.line == iseq.first_line && + events.include?(:RUBY_EVENT_CALL) + nearest = NearestISeq.new(iseq, nline, events) end end end diff --git a/test/console/break_test.rb b/test/console/break_test.rb index bd8ed86cf..239a0ef5f 100644 --- a/test/console/break_test.rb +++ b/test/console/break_test.rb @@ -838,4 +838,89 @@ def test_break_on_realoded_file end end end + + class BreakAtLineTest < ConsoleTestCase + def program path + <<~RUBY + 1| load #{path.dump} + RUBY + end + + def extra_file + <<~RUBY + a = 1 + + class C + def m + p :m + end + end + RUBY + end + + def test_break_on_line + with_extra_tempfile do |extra_file| + debug_code program(extra_file.path) do + type "break #{extra_file.path}:1" + type 'c' + assert_line_num 1 + type 'c' + end + end + end + + def program2 + <<~RUBY + 1| a = 1 + 2| b = 2 # braek 2, stop at 2 + 3| # break 3, stop at def + 4| def foo # break 4, stop at 5 (in foo) + 5| a = 2 + 6| end + 7| + 8| private def bar # break 8, stop at 9 (in bar) + 9| a = 3 + 10| end + 11| + 12| foo + 13| bar + RUBY + end + + def test_break_on_line_2 + debug_code program2 do + type 'b 2' + type 'c' + assert_line_num 2 + type 'c' + end + end + + def test_break_on_line_3 + debug_code program2 do + type 'b 3' + type 'c' + assert_line_num 4 + type 'c' + end + end + + def test_break_on_line_4 + debug_code program2 do + type 'b 4' + type 'c' + assert_line_num 5 + type 'c' + end + end + + def test_break_on_line_8 + debug_code program2 do + type 'b 8' + type 'c' + assert_line_num 9 + type 'c' + end + end + end end From 0caebcc5e36995876c2864ab63740301b533f060 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 26 Nov 2022 05:45:19 +0900 Subject: [PATCH 013/263] DAP: Allow debug command with `,command` * On the debug console, debug commands can type with `,command` (ex: `, info`) * Show welcome message on the debug console. Now this feature is experimental and `,command` can be changed in near future. --- lib/debug/server_dap.rb | 26 ++++++++++++++++++++++++-- lib/debug/session.rb | 6 +++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index a0217f3c5..7c3b17115 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -199,6 +199,13 @@ def dap_setup bytes # supportsInstructionBreakpoints: ) send_event 'initialized' + puts <<~WELCOME + Ruby REPL: You can run any Ruby expression here. + Note that output to the STDOUT/ERR printed on the TERMINAL. + [experimental] + `,COMMAND` runs `COMMAND` debug command (ex: `,info`). + `,help` to list all debug commands. + WELCOME end def send **kw @@ -425,10 +432,20 @@ def process } } + when 'evaluate' + expr = req.dig('arguments', 'expression') + if /\A\s*,(.+)\z/ =~ expr + dbg_expr = $1 + send_response req, + result: "", + variablesReference: 0 + debugger do: dbg_expr + else + @q_msg << req + end when 'stackTrace', 'scopes', 'variables', - 'evaluate', 'source', 'completions' @q_msg << req @@ -449,7 +466,11 @@ def respond req, res def puts result # STDERR.puts "puts: #{result}" - # send_event 'output', category: 'stderr', output: "PUTS!!: " + result.to_s + send_event 'output', category: 'console', output: "#{result&.chomp}\n" + end + + def ignore_output_on_suspend? + true end def event type, *args @@ -586,6 +607,7 @@ def process_protocol_request req if @frame_map[frame_id] tid, fid = @frame_map[frame_id] expr = req.dig('arguments', 'expression') + if tc = find_waiting_tc(tid) request_tc [:dap, :evaluate, req, fid, expr, context] else diff --git a/lib/debug/session.rb b/lib/debug/session.rb index f6dfb3b90..924e2eb6e 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -274,7 +274,7 @@ def process_event evt when :suspend enter_subsession if ev_args.first != :replay - output.each{|str| @ui.puts str} + output.each{|str| @ui.puts str} unless @ui.ignore_output_on_suspend? case ev_args.first when :breakpoint @@ -2069,6 +2069,10 @@ def event type, *args end end + def ignore_output_on_suspend? + false + end + def flush end end From 2081ca3e515cdb1ff0c1810c7c991c1f2c0a728e Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 28 Nov 2022 12:59:35 +0900 Subject: [PATCH 014/263] Display an accurate message when the test fails Currently, the message when the test fails is overridden by a test that checks if the remote debuggee is terminated. For example, when `assert_line_text` method is failed, the message should be `Expected to include ~ in ~`, but it will be overridden and the message will be `Expected the remote program to finish ~`. We should not assert in ensure block to prevent the problem. --- test/support/console_test_case.rb | 19 ++++++++++++++++--- test/support/test_case.rb | 2 ++ test/support/test_case_test.rb | 4 ++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 1f42fa438..bd5797c39 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -176,11 +176,23 @@ def run_test_scenario cmd, test_info check_error(/DEBUGGEE Exception/, test_info) assert_empty_queue test_info end + + if r = test_info.remote_info + assert_program_finish test_info, r.pid, :debuggee + end + + assert_program_finish test_info, pid, :debugger # result of `gets` return this exception in some platform # https://github.com/ruby/ruby/blob/master/ext/pty/pty.c#L729-L736 rescue Errno::EIO => e check_error(/DEBUGGEE Exception/, test_info) assert_empty_queue test_info, exception: e + if r = test_info.remote_info + assert_program_finish test_info, r.pid, :debuggee + end + + assert_program_finish test_info, pid, :debugger + # result of `gets` return this exception in some platform rescue Timeout::Error assert_block(create_message("TIMEOUT ERROR (#{TIMEOUT_SEC} sec)", test_info)) { false } ensure @@ -189,13 +201,14 @@ def run_test_scenario cmd, test_info read.close write.close kill_safely pid, :debugger, test_info - if name = test_info.failed_process - assert_block(create_message("Expected the #{name} program to finish", test_info)) { false } - end end end end + def assert_program_finish test_info, pid, name + assert_block(create_message("Expected the #{name} program to finish", test_info)) { wait_pid pid, TIMEOUT_SEC } + end + def prepare_test_environment(program, test_steps, &block) ENV['RUBY_DEBUG_NO_COLOR'] = 'true' ENV['RUBY_DEBUG_TEST_UI'] = 'terminal' diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 08787586c..59e3bfaa0 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -118,6 +118,8 @@ def wait_pid pid, sec end false + rescue Errno::ECHILD + true end def kill_safely pid, name, test_info diff --git a/test/support/test_case_test.rb b/test/support/test_case_test.rb index 929c67d56..b87457ac0 100644 --- a/test/support/test_case_test.rb +++ b/test/support/test_case_test.rb @@ -61,7 +61,7 @@ def steps end def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_after_scenarios - assert_raise_message(/Expected the remote program to finish/) do + assert_raise_message(/Expected the debuggee program to finish/) do prepare_test_environment(program, steps) do debug_code_on_unix_domain_socket() end @@ -69,7 +69,7 @@ def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_af end def test_the_test_fails_when_debuggee_on_tcpip_mode_doesnt_exist_after_scenarios - assert_raise_message(/Expected the remote program to finish/) do + assert_raise_message(/Expected the debuggee program to finish/) do prepare_test_environment(program, steps) do debug_code_on_tcpip() end From 1afffe3e581c848ea1686666b19871ed24e33aa2 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 28 Nov 2022 19:49:34 +0900 Subject: [PATCH 015/263] Add the test case for 525442a --- test/support/assertions_test.rb | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/support/assertions_test.rb b/test/support/assertions_test.rb index d03ad5dfb..8cf08a820 100644 --- a/test/support/assertions_test.rb +++ b/test/support/assertions_test.rb @@ -12,7 +12,7 @@ def program def test_the_helper_takes_a_string_expectation_and_escape_it assert_raise_message(/Expected to include `"foobar\\\\?/) do - debug_code(program, remote: false) do + debug_code(program) do assert_line_text("foobar?") end end @@ -49,6 +49,30 @@ def test_the_helper_raises_an_error_with_invalid_expectation end end end + + def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_after_scenarios + assert_raise_message(/Expected to include `"foobar\\\\?/) do + prepare_test_environment(program, steps) do + debug_code_on_unix_domain_socket() + end + end + end + + def test_the_test_fails_when_debuggee_on_tcpip_mode_doesnt_exist_after_scenarios + assert_raise_message(/Expected to include `"foobar\\\\?/) do + prepare_test_environment(program, steps) do + debug_code_on_tcpip() + end + end + end + + private + + def steps + Proc.new{ + assert_line_text("foobar?") + } + end end end From 4c157c1d9ad80fbcfc86de216cc27264266c8d0b Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sat, 26 Nov 2022 16:54:47 +0900 Subject: [PATCH 016/263] CDP: support Runtime.getExceptionDetails method --- lib/debug/server_cdp.rb | 79 +++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 729e7de52..8ecd5ff12 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -730,8 +730,8 @@ def process_protocol_request req code: INVALID_PARAMS, message: "'callFrameId' is an invalid" end - when 'Runtime.getProperties' - oid = req.dig('params', 'objectId') + when 'Runtime.getProperties', 'Runtime.getExceptionDetails' + oid = req.dig('params', 'objectId') || req.dig('params', 'errorObjectId') if ref = @obj_map[oid] case ref[0] when 'local' @@ -759,6 +759,8 @@ def process_protocol_request req return :retry when 'properties' request_tc [:cdp, :properties, req, oid] + when 'exception' + request_tc [:cdp, :exception, req, oid] when 'script' # TODO: Support script and global types @ui.respond req, result: [] @@ -895,6 +897,9 @@ def cdp_event args frame[:scriptId] = s_id end } + if oid = exc[:exception][:objectId] + @obj_map[oid] = ['exception'] + end end rs = result.dig(:response, :result) [rs].each{|obj| @@ -932,6 +937,8 @@ def cdp_event args } } @ui.respond req, **result + when :exception + @ui.respond req, **result end end end @@ -1051,35 +1058,7 @@ def process_cdp args result = current_frame.binding.eval(expr.to_s, '(DEBUG CONSOLE)') rescue Exception => e result = e - b = result.backtrace.map{|e| " #{e}\n"} - frames = [ - { - columnNumber: 0, - functionName: 'eval', - lineNumber: 0, - url: '' - } - ] - e.backtrace_locations&.each do |loc| - break if loc.path == __FILE__ - path = loc.absolute_path || loc.path - frames << { - columnNumber: 0, - functionName: loc.base_label, - lineNumber: loc.lineno - 1, - url: path - } - end - res[:exceptionDetails] = { - exceptionId: 1, - text: 'Uncaught', - lineNumber: 0, - columnNumber: 0, - exception: evaluate_result(result), - stackTrace: { - callFrames: frames - } - } + res[:exceptionDetails] = exceptionDetails(e, 'Uncaught') ensure output = $stdout.string $stdout = orig_stdout @@ -1158,9 +1137,47 @@ def process_cdp args prop += [internalProperty('#class', M_CLASS.bind_call(obj))] end event! :cdp_result, :properties, req, result: result, internalProperties: prop + when :exception + oid = args.shift + exc = nil + if obj = @obj_map[oid] + exc = exceptionDetails obj, obj.to_s + end + event! :cdp_result, :exception, req, exceptionDetails: exc end end + def exceptionDetails exc, text + frames = [ + { + columnNumber: 0, + functionName: 'eval', + lineNumber: 0, + url: '' + } + ] + exc.backtrace_locations&.each do |loc| + break if loc.path == __FILE__ + path = loc.absolute_path || loc.path + frames << { + columnNumber: 0, + functionName: loc.base_label, + lineNumber: loc.lineno - 1, + url: path + } + end + { + exceptionId: 1, + text: text, + lineNumber: 0, + columnNumber: 0, + exception: evaluate_result(exc), + stackTrace: { + callFrames: frames + } + } + end + def search_const b, expr cs = expr.delete_prefix('::').split('::') [Object, *b.eval('::Module.nesting')].reverse_each{|mod| From 92ec4d793f7ce1ee04d9327237baa5b6e3c5ca79 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 27 Nov 2022 12:20:44 +0900 Subject: [PATCH 017/263] CDP: Display the console when opening chrome automatically --- lib/debug/server_cdp.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 8ecd5ff12..db4ca9124 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -44,6 +44,8 @@ def setup_chrome addr, uuid } when res['id'] == 2 s_id = res.dig('result', 'sessionId') + # TODO: change id + ws_client.send sessionId: s_id, id: 100, method: 'Network.enable' ws_client.send sessionId: s_id, id: 3, method: 'Page.enable' when res['id'] == 3 @@ -59,7 +61,16 @@ def setup_chrome addr, uuid url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}", frameId: f_id } - when res['method'] == 'Page.loadEventFired' + when res['method'] == 'Network.webSocketWillSendHandshakeRequest' + s_id = res['sessionId'] + # Display the console by entering ESC key + ws_client.send sessionId: s_id, id: 101, # TODO: change id + method:"Input.dispatchKeyEvent", + params: { + type:"keyDown", + windowsVirtualKeyCode:27 # ESC key + } + when res['id'] == 101 break end end From ab3c938f8380f92a3fd3ca272909b98e44a5a9d5 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 15:18:46 +0900 Subject: [PATCH 018/263] use `info` for rdbg instruction --- lib/debug/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 25445fb9e..c2ff1fda6 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -430,7 +430,7 @@ def accept DEBUGGER__.warn "Port is saved into #{@port_save_file}" end - DEBUGGER__.warn <<~EOS + DEBUGGER__.info <<~EOS With rdbg, use the following command line: # # #{rdbg} --attach #{@local_addr.ip_address} #{@local_addr.ip_port} From 9a9cc33043886c55baeeea38a84bf49982dc4bf0 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 29 Nov 2022 15:53:50 +0900 Subject: [PATCH 019/263] Added dependabot for GitHub Actions (#843) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..b18fd2935 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'weekly' From 4b012f59c0fe8183922e4fa25455a15efb24e748 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 14:49:38 +0900 Subject: [PATCH 020/263] support `info ivars obj` `info ivars obj` shows the instance variables of `obj`. Note that this command notation also support `/pattern/` like `info ivars obj /pattern/` so that we can not show ivars of Regexp literal objects (but I believe nobody use it). --- lib/debug/session.rb | 6 +++-- lib/debug/thread_client.rb | 19 +++++++++++---- test/console/info_test.rb | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 924e2eb6e..b4b2612f2 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -738,6 +738,7 @@ def register_default_command # * It includes `self` as `%self` and a return value as `%return`. # * `i[nfo] i[var[s]]` or `i[nfo] instance` # * Show information about instance variables about `self`. + # * `info ivars ` shows the instance variables of the result of ``. # * `i[nfo] c[onst[s]]` or `i[nfo] constant[s]` # * Show information about accessible constants except toplevel constants. # * `i[nfo] g[lobal[s]]` @@ -759,8 +760,9 @@ def register_default_command request_tc [:show, :default, pat] # something useful when 'l', /^locals?/ request_tc [:show, :locals, pat] - when 'i', /^ivars?/i, /^instance[_ ]variables?/i - request_tc [:show, :ivars, pat] + when /^i\b/, /^ivars?\b/i, /^instance[_ ]variables?\b/i + expr = $~&.post_match&.strip + request_tc [:show, :ivars, pat, expr] when 'c', /^consts?/i, /^constants?/i request_tc [:show, :consts, pat] when 'g', /^globals?/i, /^global[_ ]variables?/i diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 5cce77a06..1f90df081 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -568,10 +568,18 @@ def show_locals pat end end - def show_ivars pat - if s = current_frame&.self - M_INSTANCE_VARIABLES.bind_call(s).sort.each{|iv| - value = M_INSTANCE_VARIABLE_GET.bind_call(s, iv) + def show_ivars pat, expr = nil + + if expr && !expr.empty? + _self = frame_eval(expr); + elsif _self = current_frame&.self + else + _self = nil + end + + if _self + M_INSTANCE_VARIABLES.bind_call(_self).sort.each{|iv| + value = M_INSTANCE_VARIABLE_GET.bind_call(_self, iv) puts_variable_info iv, value, pat } end @@ -1088,7 +1096,8 @@ def wait_next_action_ when :ivars pat = args.shift - show_ivars pat + expr = args.shift + show_ivars pat, expr when :consts pat = args.shift diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 47697d8fc..8eebddc7d 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -204,4 +204,51 @@ def test_info_constant end end end + + class InfoIvarsTest < ConsoleTestCase + def program + <<~RUBY + 1| class C + 2| def initialize + 3| @a = :a + 4| @b = :b + 5| end + 6| end + 7| c = C.new + 8| c + RUBY + end + + def test_ivar + debug_code program do + type 'b 5' + type 'c' + assert_line_num 5 + type 'info ivars' + assert_line_text(/@a/) + assert_line_text(/@b/) + type 'info ivars /b/' + assert_no_line_text(/@a/) + assert_line_text(/@b/) + type 'c' + end + end + + def test_ivar_obj + debug_code program do + type 'u 8' + assert_line_num 8 + type 'info ivars' + assert_no_line_text /@/ + type 'info ivars c' + assert_line_text /@a/ + assert_line_text /@b/ + type 'info ivars c /b/' + assert_no_line_text /@a/ + assert_line_text /@b/ + type 'c' + end + end + + end end From 1860db14446600b41cf9cf1be12b7749677a65ef Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 15:09:29 +0900 Subject: [PATCH 021/263] DAP: `launch` should be `localfs == true` `launch` invokes a debuggee process on the same file system so we can assume `localfs == true`. fix https://github.com/ruby/vscode-rdbg/issues/82 --- lib/debug/server_dap.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 7c3b17115..31d594d12 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -279,7 +279,8 @@ def process ## boot/configuration when 'launch' send_response req - UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') + # `launch` runs on debuggee on the same file system + UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true @nonstop = true when 'attach' From 38e376e9b73bb160802138cb283815d94e16922a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 17:38:28 +0900 Subject: [PATCH 022/263] surpress warnings with parens --- test/console/info_test.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 8eebddc7d..74221dfb9 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -239,13 +239,13 @@ def test_ivar_obj type 'u 8' assert_line_num 8 type 'info ivars' - assert_no_line_text /@/ + assert_no_line_text(/@/) type 'info ivars c' - assert_line_text /@a/ - assert_line_text /@b/ + assert_line_text(/@a/) + assert_line_text(/@b/) type 'info ivars c /b/' - assert_no_line_text /@a/ - assert_line_text /@b/ + assert_no_line_text(/@a/) + assert_line_text(/@b/) type 'c' end end From 23d47aced9cb0f2d40cbf2fbd7798be17170f5bb Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 17:39:23 +0900 Subject: [PATCH 023/263] update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a1218bad6..e383de1c5 100644 --- a/README.md +++ b/README.md @@ -660,6 +660,7 @@ The `<...>` notation means the argument. * It includes `self` as `%self` and a return value as `%return`. * `i[nfo] i[var[s]]` or `i[nfo] instance` * Show information about instance variables about `self`. + * `info ivars ` shows the instance variables of the result of ``. * `i[nfo] c[onst[s]]` or `i[nfo] constant[s]` * Show information about accessible constants except toplevel constants. * `i[nfo] g[lobal[s]]` From 016d40ede1bdc9317854957ad668af3bb4a1ffd0 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 17:39:45 +0900 Subject: [PATCH 024/263] wait for the first suspending The debugger shows "wait for debugger connection" message when it waits for the remote debugger connection because it breaks at the beggining of the program. Without this synchronization, the debugger can attach *before* the first temporary breakpoint (at the beggining of the program) and the debug scenario breaks (and test fails). It will fix some test failures. --- test/support/test_case.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 59e3bfaa0..fa2c70ea7 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -155,9 +155,19 @@ def setup_remote_debuggee(cmd) homedir = defined?(self.class.pty_home_dir) ? self.class.pty_home_dir : ENV['HOME'] remote_info = DEBUGGER__::TestCase::RemoteInfo.new(*PTY.spawn({'HOME' => homedir}, cmd)) - remote_info.r.read(1) # wait for the remote server to boot up remote_info.debuggee_backlog = [] + line = nil + + Timeout.timeout(TIMEOUT_SEC) do + line = remote_info.r.gets + remote_info.debuggee_backlog << line + + # wait for first "wait for debugger connection" output + break if /wait for debugger connection/ =~ line + redo + end + remote_info.reader_thread = Thread.new(remote_info) do |info| while data = info.r.gets info.debuggee_backlog << data From 52b5f3bd0cecea626f447d76ac2ece5fa4aaf994 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 29 Nov 2022 18:22:48 +0900 Subject: [PATCH 025/263] actions/checkout@v3 --- .github/workflows/ruby-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index cdf21efe8..1d1fa2624 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -24,7 +24,7 @@ jobs: ruby-version: ['3.1', 'head'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Ruby # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, # change this to (see https://github.com/ruby/setup-ruby#versioning): From bb31c66ec2fb3d0880c378fbd3d1f708c414f47b Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 01:56:08 +0900 Subject: [PATCH 026/263] extend `info` command * add `breakpoints` * add `watchpoints` * support abbrev subcommands --- README.md | 21 +++++++----- lib/debug/abbrev_command.rb | 66 +++++++++++++++++++++++++++++++++++ lib/debug/session.rb | 68 ++++++++++++++++++++++++++++--------- test/console/info_test.rb | 41 ++++++++++++++++++++++ 4 files changed, 172 insertions(+), 24 deletions(-) create mode 100644 lib/debug/abbrev_command.rb diff --git a/README.md b/README.md index e383de1c5..32cc066a1 100644 --- a/README.md +++ b/README.md @@ -654,21 +654,26 @@ The `<...>` notation means the argument. * `edit ` * Open on the editor. * `i[nfo]` - * Show information about current frame (local/instance variables and defined constants). -* `i[nfo] l[ocal[s]]` + * Show information about current frame (local/instance variables and defined constants). +* `i[nfo]` + * `info` has the following sub-commands. + * Sub-commands can be specified with few letters which is unambiguous, like `l` for 'locals'. +* `i[nfo] l or locals or local_variables` * Show information about the current frame (local variables) - * It includes `self` as `%self` and a return value as `%return`. -* `i[nfo] i[var[s]]` or `i[nfo] instance` + * It includes `self` as `%self` and a return value as `_return`. +* `i[nfo] i or ivars or instance_variables` * Show information about instance variables about `self`. * `info ivars ` shows the instance variables of the result of ``. -* `i[nfo] c[onst[s]]` or `i[nfo] constant[s]` +* `i[nfo] c or consts or constants` * Show information about accessible constants except toplevel constants. -* `i[nfo] g[lobal[s]]` +* `i[nfo] g or globals or global_variables` * Show information about global variables +* `i[nfo] th or threads` + * Show all threads (same as `th[read]`). +* `i[nfo] b or breakpoints or w or watchpoints` + * Show all breakpoints and watchpoints. * `i[nfo] ... /regexp/` * Filter the output with `/regexp/`. -* `i[nfo] th[read[s]]` - * Show all threads (same as `th[read]`). * `o[utline]` or `ls` * Show you available methods, constants, local variables, and instance variables in the current scope. * `o[utline] ` or `ls ` diff --git a/lib/debug/abbrev_command.rb b/lib/debug/abbrev_command.rb new file mode 100644 index 000000000..ec6a209bd --- /dev/null +++ b/lib/debug/abbrev_command.rb @@ -0,0 +1,66 @@ + +module DEBUGGER__ + class AbbrevCommand + class TrieNode + def initialize + @children = {} + @types = {} # set + end + + def append c, type + trie = (@children[c] ||= TrieNode.new) + trie.add_type type + end + + def [](c) + @children[c] + end + + def add_type type + @types[type] = true + self + end + + def types + @types.keys + end + + def type + if @types.size == 1 + @types.keys.first + else + nil + end + end + end + + # config: { type: [commands...], ... } + def initialize config + @trie = TrieNode.new + build config + end + + private def build config + config.each do |type, commands| + commands.each do |command| + trie = @trie + command.each_char do |c| + trie = trie.append(c, type) + end + end + end + end + + def search str, if_none = nil + trie = @trie + str.each_char do |c| + if trie = trie[c] + return trie.type if trie.type + else + return if_none + end + end + if_none + end + end +end diff --git a/lib/debug/session.rb b/lib/debug/session.rb index b4b2612f2..a38bb0b56 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -135,7 +135,8 @@ def initialize @tp_load_script = TracePoint.new(:script_compiled){|tp| if !has_keep_script_lines || bps_pending_until_load? - ThreadClient.current.on_load tp.instruction_sequence, tp.eval_script + eval_script = tp.eval_script unless has_keep_script_lines + ThreadClient.current.on_load tp.instruction_sequence, eval_script end } @tp_load_script.enable @@ -731,22 +732,30 @@ def register_default_command request_tc [:show, :edit, arg] end + info_subcommands = nil + info_subcommands_abbrev = nil + # * `i[nfo]` - # * Show information about current frame (local/instance variables and defined constants). - # * `i[nfo] l[ocal[s]]` + # * Show information about current frame (local/instance variables and defined constants). + # * `i[nfo]` + # * `info` has the following sub-commands. + # * Sub-commands can be specified with few letters which is unambiguous, like `l` for 'locals'. + # * `i[nfo] l or locals or local_variables` # * Show information about the current frame (local variables) - # * It includes `self` as `%self` and a return value as `%return`. - # * `i[nfo] i[var[s]]` or `i[nfo] instance` + # * It includes `self` as `%self` and a return value as `_return`. + # * `i[nfo] i or ivars or instance_variables` # * Show information about instance variables about `self`. # * `info ivars ` shows the instance variables of the result of ``. - # * `i[nfo] c[onst[s]]` or `i[nfo] constant[s]` + # * `i[nfo] c or consts or constants` # * Show information about accessible constants except toplevel constants. - # * `i[nfo] g[lobal[s]]` + # * `i[nfo] g or globals or global_variables` # * Show information about global variables + # * `i[nfo] th or threads` + # * Show all threads (same as `th[read]`). + # * `i[nfo] b or breakpoints or w or watchpoints` + # * Show all breakpoints and watchpoints. # * `i[nfo] ... /regexp/` # * Filter the output with `/regexp/`. - # * `i[nfo] th[read[s]]` - # * Show all threads (same as `th[read]`). register_command 'i', 'info', unsafe: false do |arg| if /\/(.+)\/\z/ =~ arg pat = Regexp.compile($1) @@ -755,21 +764,48 @@ def register_default_command sub = arg end + if /\A(.+?)\b(.+)/ =~ sub + sub = $1 + opt = $2.strip + opt = nil if opt.empty? + end + + if sub && !info_subcommands + info_subcommands = { + locals: %w[ locals local_variables ], + ivars: %w[ ivars instance_variables ], + consts: %w[ consts constants ], + globals:%w[ globals global_variables ], + threads:%w[ threads ], + breaks: %w[ breakpoints ], + watchs: %w[ watchpoints ], + } + + require_relative 'abbrev_command' + info_subcommands_abbrev = AbbrevCommand.new(info_subcommands) + end + + if sub + sub = info_subcommands_abbrev.search sub, :unknown + end + case sub when nil request_tc [:show, :default, pat] # something useful - when 'l', /^locals?/ + when :locals request_tc [:show, :locals, pat] - when /^i\b/, /^ivars?\b/i, /^instance[_ ]variables?\b/i - expr = $~&.post_match&.strip - request_tc [:show, :ivars, pat, expr] - when 'c', /^consts?/i, /^constants?/i + when :ivars + request_tc [:show, :ivars, pat, opt] + when :consts request_tc [:show, :consts, pat] - when 'g', /^globals?/i, /^global[_ ]variables?/i + when :globals request_tc [:show, :globals, pat] - when 'th', /threads?/ + when :threads thread_list :retry + when :breaks, :watchs + show_bps + :retry else @ui.puts "unrecognized argument for info command: #{arg}" show_help 'info' diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 74221dfb9..7c696d1e0 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -250,5 +250,46 @@ def test_ivar_obj end end + def test_ivar_abbrev + debug_code program do + type 'b 5' + type 'c' + assert_line_num 5 + + %w[ i iv iva ivar ivars + in ins inst insta instan instanc instance + instance_ instance_v instance_va instance_variable instance_variables].each{|c| + type "info #{c}" + assert_line_text(/@a/) + assert_line_text(/@b/) + } + type 'c' + end + end + end + + class InfoBreaksTest < ConsoleTestCase + def program + <<~RUBY + 1| @a = 1 + 2| @b = 2 + 3| @c = 3 + RUBY + end + + def test_ivar_abbrev + debug_code program do + type 'next' + assert_line_num 2 + type 'break 3' + type 'watch @a' + type 'i b' + assert_line_text(/:3/) + assert_line_text(/@a/) + type 'c' + assert_line_num 3 + type 'c' + end + end end end From bb97fbd76ae0c527c0aa06c7158ecb415110e58c Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 03:51:21 +0900 Subject: [PATCH 027/263] `config show_evaledsrc` Now debugger records actually evaluated source code with (1) `eval` methods or (2) loaded files. For (1) sometimes `eval` with existing filename, for example erb, haml and so on. For (2) sometimes the contents will be changed after loading especially on development phase. `config show_evaledsrc` configuration (default: `false`) controls which should be shown for the source code: * true: actually evaluated source code * false (default): current file system's source code For the erb, haml etc from files, `false`'s behavior seems nice so I added this configuration (with `false` default). --- README.md | 1 + lib/debug/config.rb | 1 + lib/debug/source_repository.rb | 58 +++++++++++++++++++++++----------- test/console/config_test.rb | 38 ++++++++++++++++++++++ 4 files changed, 79 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 32cc066a1..f5a1b533b 100644 --- a/README.md +++ b/README.md @@ -469,6 +469,7 @@ config set no_color true * UI * `RUBY_DEBUG_LOG_LEVEL` (`log_level`): Log level same as Logger (default: WARN) * `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10) + * `RUBY_DEBUG_SHOW_EVALEDSRC` (`show_evaledsrc`): Show actually evaluated source (default: false) * `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2) * `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shorten PATH (like $(Gem)/foo.rb) (default: false) * `RUBY_DEBUG_NO_COLOR` (`no_color`): Do not use colorize (default: false) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 70ca12487..f0a626c02 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -14,6 +14,7 @@ module DEBUGGER__ # UI setting log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"], show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"], + show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"], show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"], use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"], no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"], diff --git a/lib/debug/source_repository.rb b/lib/debug/source_repository.rb index 76142dd1e..27cf98878 100644 --- a/lib/debug/source_repository.rb +++ b/lib/debug/source_repository.rb @@ -6,6 +6,22 @@ module DEBUGGER__ class SourceRepository include Color + def file_src iseq + if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path) + File.readlines(path, chomp: true) + end + end + + def get iseq + return unless iseq + + if CONFIG[:show_evaledsrc] + orig_src(iseq) || file_src(iseq) + else + file_src(iseq) || orig_src(iseq) + end + end + if RubyVM.respond_to? :keep_script_lines # Ruby 3.1 and later RubyVM.keep_script_lines = true @@ -29,17 +45,13 @@ def add iseq, src end end - def get iseq - return unless iseq - - if lines = iseq.script_lines&.map(&:chomp) - lines + def orig_src iseq + lines = iseq.script_lines&.map(&:chomp) + line = iseq.first_line + if line > 1 + lines = [*([''] * (line - 1)), *lines] else - if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path) - File.readlines(path, chomp: true) - else - nil - end + lines end end @@ -63,15 +75,22 @@ def initialize end def add iseq, src - if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path) + path = (iseq.absolute_path || iseq.path) + + if path && File.exist?(path) reloaded = @files.has_key? path - add_path path - return path, reloaded - elsif src + + if src + add_iseq iseq, src + return path, reloaded + else + add_path path + return path, reloaded + end + else add_iseq iseq, src + nil end - - nil end private def all_iseq iseq, rs = [] @@ -87,7 +106,8 @@ def add iseq, src if line > 1 src = ("\n" * (line - 1)) + src end - si = SrcInfo.new(src.lines) + + si = SrcInfo.new(src.each_line.map{|l| l.chomp}) all_iseq(iseq).each{|e| e.instance_variable_set(:@debugger_si, si) e.freeze @@ -102,7 +122,7 @@ def add iseq, src private def get_si iseq return unless iseq - + if iseq.instance_variable_defined?(:@debugger_si) iseq.instance_variable_get(:@debugger_si) elsif @files.has_key?(path = (iseq.absolute_path || iseq.path)) @@ -112,7 +132,7 @@ def add iseq, src end end - def get iseq + def orig_src iseq if si = get_si(iseq) si.src end diff --git a/test/console/config_test.rb b/test/console/config_test.rb index 102329165..9925c017d 100644 --- a/test/console/config_test.rb +++ b/test/console/config_test.rb @@ -105,6 +105,44 @@ def test_show_src_lines_control_the_lines_displayed_on_breakpoint end end + class ShowOrigSrcTest < ConsoleTestCase + def program + <<~RUBY + 1| binding.eval < Date: Tue, 29 Nov 2022 17:58:45 -0700 Subject: [PATCH 028/263] =?UTF-8?q?=F0=9F=90=9B=20Respect=20breakpoints=20?= =?UTF-8?q?even=20when=20in=20a=20skipped=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/debug/server_dap.rb | 2 +- test/protocol/call_stack_with_skip_dap_test.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 31d594d12..be3f34eda 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -749,7 +749,7 @@ def process_dap args next if i < start_frame path = frame.realpath || frame.path - next if skip_path?(path) + next if skip_path?(path) && !SESSION.stop_stepping?(path, frame.location.lineno, SESSION.subsession_id) break if (levels -= 1) < 0 source_name = path ? File.basename(path) : frame.location.to_s diff --git a/test/protocol/call_stack_with_skip_dap_test.rb b/test/protocol/call_stack_with_skip_dap_test.rb index 52cec55a2..32b94be09 100644 --- a/test/protocol/call_stack_with_skip_dap_test.rb +++ b/test/protocol/call_stack_with_skip_dap_test.rb @@ -58,5 +58,21 @@ def test_it_skips_a_path ensure ENV['RUBY_DEBUG_SKIP_PATH'] = nil end + + def test_it_does_not_skip_a_path_if_there_is_a_breakpoint + with_extra_tempfile do |extra_file| + ENV['RUBY_DEBUG_SKIP_PATH'] = extra_file.path + run_protocol_scenario(program(extra_file.path), cdp: false) do + req_add_breakpoint 2, path: extra_file.path + req_continue + + assert_equal([File.basename(extra_file.path), File.basename(temp_file_path)], req_stacktrace_file_names) + + req_terminate_debuggee + end + end + ensure + ENV['RUBY_DEBUG_SKIP_PATH'] = nil + end end end From 0e3a9497ebcc2375476be7eca4277fbfa5f843a3 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 11:14:04 +0900 Subject: [PATCH 029/263] trivial fix https://github.com/ruby/debug/pull/850#issuecomment-1331554223 --- lib/debug/server_dap.rb | 2 +- lib/debug/session.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index be3f34eda..cf50395e1 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -749,7 +749,7 @@ def process_dap args next if i < start_frame path = frame.realpath || frame.path - next if skip_path?(path) && !SESSION.stop_stepping?(path, frame.location.lineno, SESSION.subsession_id) + next if skip_path?(path) && !SESSION.stop_stepping?(path, frame.location.lineno) break if (levels -= 1) < 0 source_name = path ? File.basename(path) : frame.location.to_s diff --git a/lib/debug/session.rb b/lib/debug/session.rb index a38bb0b56..74eb6b631 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -151,10 +151,10 @@ def active? !@q_evt.closed? end - def stop_stepping? file, line, subsession_id + def stop_stepping? file, line, subsession_id = nil if @bps.has_key? [file, line] true - elsif @subsession_id != subsession_id + elsif subsession_id && @subsession_id != subsession_id true else false From 74b0d9d5104c45e9bf3a825988a31414509797db Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 17:51:18 +0900 Subject: [PATCH 030/263] write file before running `debug_code` On MacOS sometimes it fails. ``` uninitialized constant Foo (NameError) ``` Try to make sure that the file is completely written. --- test/console/backtrace_test.rb | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index 818fe609e..ba0fe85c0 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -116,33 +116,41 @@ def test_backtrace_takes_both_number_and_pattern end def test_frame_filtering_works_with_unexpanded_path_and_expanded_skip_path - foo_file = 'class Foo; def bar; debugger; end; end' + foo_path = "#{pty_home_dir}/foo_#{Time.now.to_i}.rb" + foo_file = <<~RUBY + class Foo + def bar + debugger + end + end + RUBY + program = <<~RUBY - 1| load "~/foo.rb" + 1| load "~/#{File.basename(foo_path)}" 2| Foo.new.bar RUBY begin - File.open("#{pty_home_dir}/foo.rb", 'w+').close + File.open(foo_path, 'w+').close rescue Errno::EACCES, Errno::EPERM omit "Skip test with load files. Cannot create files in HOME directory." end + file = File.open(foo_path, 'w+') { |f| f.write(foo_file) } debug_code(program) do - type "file = File.open('#{pty_home_dir}/foo.rb', 'w+') { |f| f.write('#{foo_file}') }" type 'c' type 'bt' assert_line_text(/Foo#bar/) - assert_line_text(/~\/foo\.rb/) - type "DEBUGGER__::CONFIG[:skip_path] = '#{pty_home_dir}/foo.rb'" + assert_line_text(/~\/foo_\d+.rb/) + type "eval DEBUGGER__::CONFIG[:skip_path] = '#{foo_path}'" type 'bt' - assert_no_line_text(/Foo#bar/) # ~/foo.rb should match foo.rb's absolute path and be skipped + assert_no_line_text(/Foo#bar/) # ~/foo....rb should match foo.rb's absolute path and be skipped assert_no_line_text(/~\/foo\.rb/) type 'c' end ensure - if File.exist? "#{pty_home_dir}/foo.rb" - File.unlink "#{pty_home_dir}/foo.rb" + if File.exist? foo_path + File.unlink foo_path end end end From ba72e8450964e3a3a7f6ab40c43ef06ce6f0f677 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 18:21:33 +0900 Subject: [PATCH 031/263] use backquote. --- lib/debug/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index f0a626c02..a5d999e41 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -34,7 +34,7 @@ module DEBUGGER__ nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"], stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"], init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], - commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"], + commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"], save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], From eb42234ffcfea81e82788ec12466326a90c9fcc8 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 21:47:30 +0900 Subject: [PATCH 032/263] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f5a1b533b..3cb4a72d3 100644 --- a/README.md +++ b/README.md @@ -489,7 +489,7 @@ config set no_color true * `RUBY_DEBUG_NONSTOP` (`nonstop`): Nonstop mode (default: false) * `RUBY_DEBUG_STOP_AT_LOAD` (`stop_at_load`): Stop at just loading location (default: false) * `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop - * `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. commands should be separated by ';;' + * `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. Commands should be separated by `;;` * `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb) (default: false) * `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: ~/.rdbg_history) * `RUBY_DEBUG_SAVE_HISTORY` (`save_history`): maximum save history lines (default: 10000) From 81a812e36c794b5e2666a6d8751febb5f6cf8e5e Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 30 Nov 2022 19:08:12 +0900 Subject: [PATCH 033/263] use freeport with --port=0 `setup_remote_debuggee` wait for "waiting" message and "port informatioin" message, too. --- test/support/test_case.rb | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index fa2c70ea7..5f8ed7a1b 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -158,14 +158,22 @@ def setup_remote_debuggee(cmd) remote_info.debuggee_backlog = [] line = nil + msg1 = msg2 = nil Timeout.timeout(TIMEOUT_SEC) do line = remote_info.r.gets remote_info.debuggee_backlog << line - # wait for first "wait for debugger connection" output - break if /wait for debugger connection/ =~ line - redo + # wait for two lines (order is unstable) + case line + when /\ADEBUGGER: Debugger can attach via/ + msg1 = true + when /\ADEBUGGER: wait for debugger connection/ + msg2 = true + end + + break if msg1 && msg2 + redo # loop end remote_info.reader_thread = Thread.new(remote_info) do |info| @@ -191,14 +199,16 @@ def setup_unix_domain_socket_remote_debuggee remote_info end - # search free port by opening server socket with port 0 - Socket.tcp_server_sockets(0).tap do |ss| - TCPIP_PORT = ss.first.local_address.ip_port - end.each{|s| s.close} - def setup_tcpip_remote_debuggee - remote_info = setup_remote_debuggee("#{RDBG_EXECUTABLE} -O --port=#{TCPIP_PORT} -- #{temp_file_path}") - remote_info.port = TCPIP_PORT + remote_info = setup_remote_debuggee("#{RDBG_EXECUTABLE} -O --port=0 -- #{temp_file_path}") + port = nil + remote_info.debuggee_backlog.each{|line| + if /Debugger can attach via TCP\/IP \(.+:(\d+)\)/ =~ line + port = $1.to_i + end + } + raise "can not find TCP/IP port with backlog: #{remote_info.debuggee_backlog.inspect}" unless port + remote_info.port = port Timeout.timeout(TIMEOUT_SEC) do sleep 0.001 until remote_info.debuggee_backlog.join.include? remote_info.port.to_s end From 79bf499282d311bf61a49444395d32fb75ce269a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 03:40:42 +0900 Subject: [PATCH 034/263] abbrev candidates feature --- lib/debug/abbrev_command.rb | 11 +++++++++++ lib/debug/session.rb | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/debug/abbrev_command.rb b/lib/debug/abbrev_command.rb index ec6a209bd..96e8b2b1c 100644 --- a/lib/debug/abbrev_command.rb +++ b/lib/debug/abbrev_command.rb @@ -32,6 +32,16 @@ def type nil end end + + def candidates + @children.map{|c, n| + ss = n.candidates + ss.empty? ? c : + ss.map{|s| + c+s + } + }.flatten + end end # config: { type: [commands...], ... } @@ -60,6 +70,7 @@ def search str, if_none = nil return if_none end end + yield trie.candidates.map{|s| str + s} if block_given? if_none end end diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 74eb6b631..33647a1f0 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -786,7 +786,10 @@ def register_default_command end if sub - sub = info_subcommands_abbrev.search sub, :unknown + sub = info_subcommands_abbrev.search sub, :unknown do |candidates| + # note: unreached now + @ui.puts "Ambiguous command '#{sub}': #{candidates.join(' ')}" + end end case sub From 7cb4cfcc3efa9a2a7d2a14cefb852ae0f62700d2 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 03:50:15 +0900 Subject: [PATCH 035/263] take care exceptions from `const_get` `const_get` can raise an error so it should be handled. --- lib/debug/server_cdp.rb | 6 +++++- lib/debug/server_dap.rb | 6 +++++- lib/debug/thread_client.rb | 6 +++++- test/console/info_test.rb | 10 ++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index db4ca9124..99abffcfa 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -1194,7 +1194,11 @@ def search_const b, expr [Object, *b.eval('::Module.nesting')].reverse_each{|mod| if cs.all?{|c| if mod.const_defined?(c) - mod = mod.const_get(c) + begin + mod = mod.const_get(c) + rescue Exception + false + end else false end diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index cf50395e1..288db814d 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -960,7 +960,11 @@ def search_const b, expr [Object, *b.eval('::Module.nesting')].reverse_each{|mod| if cs.all?{|c| if mod.const_defined?(c) - mod = mod.const_get(c) + begin + mod = mod.const_get(c) + rescue Exception + false + end else false end diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 1f90df081..2d184a76a 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -608,7 +608,11 @@ def show_consts pat, only_self: false c.constants(false).sort.each{|name| next if names.has_key? name names[name] = nil - value = c.const_get(name) + begin + value = c.const_get(name) + rescue Exception => e + value = e + end puts_variable_info name, value, pat } } diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 7c696d1e0..ae72f42af 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -203,6 +203,16 @@ def test_info_constant type 'c' end end + + def test_info_constant_twice + debug_code program do + type 'i c' # on Ruby 3.2, `Set` loads `set.rb` + type 'i c' # on Ruby 3.2, accessing `SortedSet` raises an error + # # Date: Fri, 2 Dec 2022 04:26:03 +0900 Subject: [PATCH 036/263] support `info consts ClassOrModule` --- lib/debug/session.rb | 3 +- lib/debug/thread_client.rb | 56 +++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 33647a1f0..026473772 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -748,6 +748,7 @@ def register_default_command # * `info ivars ` shows the instance variables of the result of ``. # * `i[nfo] c or consts or constants` # * Show information about accessible constants except toplevel constants. + # * `info consts ` shows the constants of a class/module of the result of `` # * `i[nfo] g or globals or global_variables` # * Show information about global variables # * `i[nfo] th or threads` @@ -800,7 +801,7 @@ def register_default_command when :ivars request_tc [:show, :ivars, pat, opt] when :consts - request_tc [:show, :consts, pat] + request_tc [:show, :consts, pat, opt] when :globals request_tc [:show, :globals, pat] when :threads diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 2d184a76a..a35eedf42 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -569,7 +569,6 @@ def show_locals pat end def show_ivars pat, expr = nil - if expr && !expr.empty? _self = frame_eval(expr); elsif _self = current_frame&.self @@ -585,18 +584,39 @@ def show_ivars pat, expr = nil end end - def show_consts pat, only_self: false - if s = current_frame&.self + def iter_consts c, names = {} + c.constants(false).sort.each{|name| + next if names.has_key? name + names[name] = nil + begin + value = c.const_get(name) + rescue Exception => e + value = e + end + yield name, value + } + end + + def get_consts expr = nil, only_self: false, &block + if expr && !expr.empty? + _self = frame_eval(expr) + if M_KIND_OF_P.bind_call(_self, Module) + iter_consts _self, &block + return + else + raise "#{_self.inspect} (by #{expr}) is not a Module." + end + elsif _self = current_frame&.self cs = {} - if M_KIND_OF_P.bind_call(s, Module) - cs[s] = :self + if M_KIND_OF_P.bind_call(_self, Module) + cs[_self] = :self else - s = M_CLASS.bind_call(s) - cs[s] = :self unless only_self + _self = M_CLASS.bind_call(_self) + cs[_self] = :self unless only_self end unless only_self - s.ancestors.each{|c| break if c == Object; cs[c] = :ancestors} + _self.ancestors.each{|c| break if c == Object; cs[c] = :ancestors} if b = current_frame&.binding b.eval('::Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c} end @@ -605,20 +625,17 @@ def show_consts pat, only_self: false names = {} cs.each{|c, _| - c.constants(false).sort.each{|name| - next if names.has_key? name - names[name] = nil - begin - value = c.const_get(name) - rescue Exception => e - value = e - end - puts_variable_info name, value, pat - } + iter_consts c, names, &block } end end + def show_consts pat, expr = nil, only_self: false + get_consts expr, only_self: only_self do |name, value| + puts_variable_info name, value, pat + end + end + SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze def show_globals pat global_variables.sort.each{|name| @@ -1105,7 +1122,8 @@ def wait_next_action_ when :consts pat = args.shift - show_consts pat + expr = args.shift + show_consts pat, expr when :globals pat = args.shift From 1b8e120efc5bd58e9e5e97cf8957b613f349b239 Mon Sep 17 00:00:00 2001 From: binarygit Date: Wed, 23 Nov 2022 12:57:42 +0545 Subject: [PATCH 037/263] Update README.md --- README.md | 4 ++-- misc/README.md.erb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3cb4a72d3..04c31e4ba 100644 --- a/README.md +++ b/README.md @@ -839,11 +839,11 @@ It is useful if you only want to call a debug command and don't want to stop the ``` def initialize @a = 1 - binding.b do: 'watch @a' + binding.b do: 'info \n watch @a' end ``` -On this case, register a watch breakpoint for `@a` and continue to run. +On this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend. It is useful if you have operations before suspend. diff --git a/misc/README.md.erb b/misc/README.md.erb index 99195e138..5fa685b35 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -568,11 +568,11 @@ It is useful if you only want to call a debug command and don't want to stop the ``` def initialize @a = 1 - binding.b do: 'watch @a' + binding.b do: 'info \n watch @a' end ``` -On this case, register a watch breakpoint for `@a` and continue to run. +On this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend. It is useful if you have operations before suspend. From 699a31e1adfcf51cf4f6f9e84f862e45072f83b4 Mon Sep 17 00:00:00 2001 From: Shunichi Ikegami Date: Fri, 2 Dec 2022 15:14:51 +0900 Subject: [PATCH 038/263] Support Process.daemon --- lib/debug/session.rb | 18 +++++++++++++++-- test/console/daemon_test.rb | 32 +++++++++++++++++++++++++++++++ test/support/console_test_case.rb | 8 ++++---- 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 test/console/daemon_test.rb diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 026473772..994756dee 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2421,8 +2421,20 @@ def fork(&given_block) end end - private def __fork_setup_for_debugger - fork_mode = CONFIG[:fork_mode] + module DaemonInterceptor + def daemon + return super unless defined?(SESSION) && SESSION.active? + + _, child_hook = __fork_setup_for_debugger(:child) + + super.tap do + child_hook.call + end + end + end + + private def __fork_setup_for_debugger fork_mode = nil + fork_mode ||= CONFIG[:fork_mode] if fork_mode == :both && CONFIG[:parent_on_fork] fork_mode = :parent @@ -2487,6 +2499,7 @@ def trap sig, *command, &command_proc module ::Process class << self prepend ForkInterceptor + prepend DaemonInterceptor end end @@ -2522,6 +2535,7 @@ class << self module ::Process class << self prepend ForkInterceptor + prepend DaemonInterceptor end end end diff --git a/test/console/daemon_test.rb b/test/console/daemon_test.rb new file mode 100644 index 000000000..87049b405 --- /dev/null +++ b/test/console/daemon_test.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require_relative '../support/console_test_case' + +module DEBUGGER__ + class DaemonTest < ConsoleTestCase + def program + # Ignore SIGHUP since the test debuggee receives SIGHUP after Process.daemon. + # When manualy debugging a daemon, it doesn't receive SIGHUP. + # I don't know why. + <<~'RUBY' + 1| trap(:HUP, 'IGNORE') + 2| puts 'Daemon starting' + 3| Process.daemon + 4| puts 'Daemon started' + RUBY + end + + def test_daemon + # The program can't be debugged locally since the parent process exits when Process.daemon is called. + debug_code program, remote: :remote_only do + type 'b 3' + type 'c' + assert_line_num 3 + type 'b 4' + type 'c' + assert_line_num 4 + type 'c' + end + end + end +end diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index bd5797c39..61b87095a 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -91,10 +91,10 @@ def debug_code(program, remote: true, &test_steps) if remote && !NO_REMOTE && MULTITHREADED_TEST begin th = [ - new_thread { debug_code_on_local }, + (new_thread { debug_code_on_local } unless remote == :remote_only), new_thread { debug_code_on_unix_domain_socket }, new_thread { debug_code_on_tcpip }, - ] + ].compact th.each do |t| if fail_msg = t.join.value @@ -109,11 +109,11 @@ def debug_code(program, remote: true, &test_steps) th.each {|t| t.join} end elsif remote && !NO_REMOTE - debug_code_on_local + debug_code_on_local unless remote == :remote_only debug_code_on_unix_domain_socket debug_code_on_tcpip else - debug_code_on_local + debug_code_on_local unless remote == :remote_only end end end From f24a6f911021f60c0b02b4fb85470d16afe275d0 Mon Sep 17 00:00:00 2001 From: Shunichi Ikegami Date: Fri, 2 Dec 2022 16:21:57 +0900 Subject: [PATCH 039/263] Warn against debugging Process.daemon locally. --- lib/debug/session.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 994756dee..ada5d4576 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -151,6 +151,10 @@ def active? !@q_evt.closed? end + def remote? + @ui.remote? + end + def stop_stepping? file, line, subsession_id = nil if @bps.has_key? [file, line] true @@ -2427,6 +2431,10 @@ def daemon _, child_hook = __fork_setup_for_debugger(:child) + unless SESSION.remote? + DEBUGGER__.warn "Can't debug the code after Process.daemon locally. Use the remote debugging feature." + end + super.tap do child_hook.call end From 41611c409a82903b5478bba134b331809be9a326 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 17:16:42 +0900 Subject: [PATCH 040/263] update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 04c31e4ba..243c3acbc 100644 --- a/README.md +++ b/README.md @@ -667,6 +667,7 @@ The `<...>` notation means the argument. * `info ivars ` shows the instance variables of the result of ``. * `i[nfo] c or consts or constants` * Show information about accessible constants except toplevel constants. + * `info consts ` shows the constants of a class/module of the result of `` * `i[nfo] g or globals or global_variables` * Show information about global variables * `i[nfo] th or threads` From 17c37958d0f59f9738b5c71edd6d12dbfdc49f22 Mon Sep 17 00:00:00 2001 From: Shunichi Ikegami Date: Fri, 2 Dec 2022 17:16:21 +0900 Subject: [PATCH 041/263] Fix typo in CONTRIBUTING.md --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ab97e0e0..22c8bfcf0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -166,7 +166,7 @@ module DEBUGGER__ 9| end RUBY end - + def test_1629720194 debug_code(program) do type 's' @@ -272,7 +272,7 @@ To run the test generator, you can enter `$ bin/gentest target.rb --open=vscode` Also, if you enter `$ bin/gentest target.rb --open=chrome` there, Chrome will be executed. If you need to modify existing tests, it is basically a good idea to regenerate them by the test generator instead of rewriting them directly. Please refer to [the Microsoft "Debug Adapter Protocol" article](https://microsoft.github.io/debug-adapter-protocol/specification) to learn more about DAP formats. -Please refer to [Procol viewer for "Chrome DevTools Protocol"](https://chromedevtools.github.io/devtools-protocol/) to learn more about CDP formats. +Please refer to [the "Chrome DevTools Protocol" official documentation](https://chromedevtools.github.io/devtools-protocol/) to learn more about CDP formats. 2. High-level tests @@ -352,7 +352,7 @@ Sends request to rdbg to set exception breakpoints. e.g. req_set_exception_breakpoints([{ name: "RuntimeError", condition: "a == 1" }]) ``` -Please note that `setExceptionBreakpoints` resets all exception breakpoints in every request. +Please note that `setExceptionBreakpoints` resets all exception breakpoints in every request. So the following code will only set breakpoint for `Exception`. From 81716cf3eb60ab3b53f7eb1ee2b5eea3ef36657d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 18:08:48 +0900 Subject: [PATCH 042/263] don't show if logfile is closed --- lib/debug/session.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index ada5d4576..98c010bcd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2343,6 +2343,7 @@ def self.debug(&b) def self.log level, msg if check_loglevel level @logfile = STDERR unless defined? @logfile + return if @logfile.closed? if defined? SESSION pi = SESSION.process_info From 882d595a7d535d60fa4a7da24e6eb3f2661d2a94 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 18:24:13 +0900 Subject: [PATCH 043/263] use `TOPLEVEL_BINDING` if no binding Configuration with `~/.rdbgrc` it is possible that the `current_frame` is nil. This patch uses `TOPLEVEL_BINDING` for such cases. --- lib/debug/thread_client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index a35eedf42..994e6a36f 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -427,7 +427,7 @@ def frame_eval_core src, b, binding_location: false def frame_eval src, re_raise: false, binding_location: false @success_last_eval = false - b = current_frame.eval_binding + b = current_frame&.eval_binding || TOPLEVEL_BINDING special_local_variables current_frame do |name, var| b.local_variable_set(name, var) if /\%/ !~ name @@ -810,7 +810,7 @@ def make_breakpoint args case args.first when :method klass_name, op, method_name, cond, cmd, path = args[1..] - bp = MethodBreakpoint.new(current_frame.eval_binding, klass_name, op, method_name, cond: cond, command: cmd, path: path) + bp = MethodBreakpoint.new(current_frame&.eval_binding || TOPLEVEL_BINDING, klass_name, op, method_name, cond: cond, command: cmd, path: path) begin bp.enable rescue NameError => e From d32b1574b6144aef96547d753c42ff86a3c02610 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 17:54:56 +0900 Subject: [PATCH 044/263] support reset `no_sigint_hook` config ```ruby require 'debug' # no_sigint_hook: true require 'debug/start' # no_sigint_hook: false ``` In this case SIGINT should be a breakpoint but it was not enabled. --- lib/debug/config.rb | 6 ++++++ lib/debug/local.rb | 25 +++++++++++++++---------- lib/debug/session.rb | 11 +++++++++++ lib/debug/start.rb | 2 +- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index a5d999e41..7ffdd741c 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -149,6 +149,12 @@ def update conf if_updated old_conf, conf, :sigdump_sig do |old_sig, new_sig| setup_sigdump old_sig, new_sig end + + if_updated old_conf, conf, :no_sigint_hook do |old, new| + if defined?(SESSION) + SESSION.set_no_sigint_hook old, new + end + end end private def if_updated old_conf, new_conf, key diff --git a/lib/debug/local.rb b/lib/debug/local.rb index 9cbecd1cd..77f6caa66 100644 --- a/lib/debug/local.rb +++ b/lib/debug/local.rb @@ -13,23 +13,28 @@ def remote? false end - def activate session, on_fork: false - unless CONFIG[:no_sigint_hook] - prev_handler = trap(:SIGINT){ - if session.active? - ThreadClient.current.on_trap :SIGINT - end - } - session.intercept_trap_sigint_start prev_handler - end + def activate_sigint + prev_handler = trap(:SIGINT){ + if SESSION.active? + ThreadClient.current.on_trap :SIGINT + end + } + SESSION.intercept_trap_sigint_start prev_handler end - def deactivate + def deactivate_sigint if SESSION.intercept_trap_sigint? prev = SESSION.intercept_trap_sigint_end trap(:SIGINT, prev) end + end + + def activate session, on_fork: false + activate_sigint unless CONFIG[:no_sigint_hook] + end + def deactivate + deactivate_sigint @console.deactivate end diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 98c010bcd..1402d554a 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1926,6 +1926,17 @@ def postmortem=(is_enable) end end + def set_no_sigint_hook old, new + return unless old != new + return unless @ui.respond_to? :activate_sigint + + if old # no -> yes + @ui.activate_sigint + else + @ui.deactivate_sigint + end + end + def save_int_trap cmd prev, @intercepted_sigint_cmd = @intercepted_sigint_cmd, cmd prev diff --git a/lib/debug/start.rb b/lib/debug/start.rb index ce5ebf548..6cdfb608c 100644 --- a/lib/debug/start.rb +++ b/lib/debug/start.rb @@ -2,4 +2,4 @@ require_relative 'session' return unless defined?(DEBUGGER__) -DEBUGGER__.start +DEBUGGER__.start no_sigint_hook: false From 31cb9ee1c883e69ff6ff2a5e851145c942989a01 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 18:58:05 +0900 Subject: [PATCH 045/263] `RUBY_DEBUG_LAZY` boot option With `RUBY_DEBUG_LAZY=1`, `require 'debug'` doesn't start a session but start when `debugger` method is called (or `require 'debug/start'` is called). This feature is experimental. https://github.com/ruby/debug/issues/797 --- lib/debug.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/debug.rb b/lib/debug.rb index 15ebccb62..a4890123a 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true -require_relative 'debug/session' -return unless defined?(DEBUGGER__) -DEBUGGER__::start no_sigint_hook: true, nonstop: true +if ENV['RUBY_DEBUG_LAZY'] + require_relative 'debug/prelude' +else + require_relative 'debug/session' + return unless defined?(DEBUGGER__) + DEBUGGER__::start no_sigint_hook: true, nonstop: true +end From 95df2c5e1567c70f95ad8d134a088f5a99883141 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 22:07:22 +0900 Subject: [PATCH 046/263] show more information for UNIX domain sockets If there are some debuggee processes open debug ports with UNIX domain socket, `rdbg -A` client lists possible ports. This patch add more information (pid, $0) for this list. --- lib/debug/client.rb | 29 +++++++++++++++++++++++------ lib/debug/server.rb | 3 ++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/debug/client.rb b/lib/debug/client.rb index f3023f12f..2d7d31b56 100644 --- a/lib/debug/client.rb +++ b/lib/debug/client.rb @@ -25,6 +25,9 @@ def util name when 'list-socks' cleanup_unix_domain_sockets puts list_connections + when 'list-socks-verbose' + cleanup_unix_domain_sockets + puts list_connections verbose: true when 'setup-autoload' setup_autoload else @@ -91,10 +94,24 @@ def cleanup_unix_domain_sockets end end - def list_connections - Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*').find_all do |path| + def list_connections verbose: false + socks = Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*').find_all do |path| File.socket?(path) end + + if verbose + socks = socks.map{|sock_path| + Socket.unix(sock_path){|sock| + sock.puts "info cookie: #{CONFIG[:cookie] || '-'}" + pid = sock.gets.chomp + _dbg = sock.gets.chomp + _unm = sock.gets.chomp + [sock_path, pid] + } + } + end + + socks end end @@ -148,18 +165,18 @@ def connect_unix name = nil end else Client.cleanup_unix_domain_sockets - files = Client.list_connections + files = Client.list_connections verbose: true case files.size when 0 $stderr.puts "No debug session is available." exit when 1 - @s = Socket.unix(files.first) + @s = Socket.unix(files.first.first) else $stderr.puts "Please select a debug session:" - files.each{|f| - $stderr.puts " #{File.basename(f)}" + files.each{|(f, desc)| + $stderr.puts " #{File.basename(f)} (#{desc})" } exit end diff --git a/lib/debug/server.rb b/lib/debug/server.rb index c2ff1fda6..64bd3bff4 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -144,7 +144,8 @@ def greeting # TODO: protocol version if v != VERSION - raise GreetingError, "Incompatible version (server:#{VERSION} and client:#{$1})" + @sock.puts msg = "out DEBUGGER: Incompatible version (server:#{VERSION} and client:#{$1})" + raise GreetingError, msg end parse_option(params) From 8eb0b30c82d7cd5debee143e2a1165da0ff67019 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 2 Dec 2022 23:20:18 +0900 Subject: [PATCH 047/263] v1.7.0 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index a27451118..df6c80e4a 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.7.0dev" + VERSION = "1.7.0" end From ec5ae5aebd61a99dc84028d8dffa8e7e165c1ec6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 3 Dec 2022 00:22:05 +0900 Subject: [PATCH 048/263] rewrite TODO --- TODO.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 91973e3fa..cc511416e 100644 --- a/TODO.md +++ b/TODO.md @@ -2,22 +2,22 @@ ## Basic functionality -* Support Ractors -* Signal (SIGINT) trap handling +* Support Fibers and Ractors ## UI +* Multi-line support * Completion for Ruby's code * Interactive breakpoint setting * Interactive record & play debugging * irb integration -* Web browser integrated UI -* History file ## Debug command -* Breakpoints - * Lightweight pending method break points with Ruby 3.1 feature (TP:method_added) * Watch points - * Lightweight watchpoints for instance variables with Ruby 3.1 features (TP:ivar_set) -* Faster `next`/`finish` command by specifying target code. + * Lightweight watchpoints for instance variables with Ruby 3.3 features (TP:ivar_set) +* Alias + +## Debug port + +* Debug port for monitoring From b4ec2d7932c8a37f8891f648f8f6e632ffa13da4 Mon Sep 17 00:00:00 2001 From: akira yamada Date: Mon, 5 Dec 2022 01:06:38 +0900 Subject: [PATCH 049/263] suppress warnings about deprecated global variables --- lib/debug/server_cdp.rb | 6 ++++-- lib/debug/server_dap.rb | 8 +++++--- lib/debug/thread_client.rb | 11 +++++++++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 99abffcfa..6d2dacb16 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -696,6 +696,8 @@ def puts result end class Session + include GlobalVariablesHelper + # FIXME: unify this method with ThreadClient#propertyDescriptor. def get_type obj case obj @@ -750,7 +752,7 @@ def process_protocol_request req fid = @frame_map[frame_id] request_tc [:cdp, :scope, req, fid] when 'global' - vars = global_variables.sort.map do |name| + vars = safe_global_variables.sort.map do |name| gv = eval(name.to_s) prop = { name: name, @@ -1040,7 +1042,7 @@ def process_cdp args case expr # Chrome doesn't read instance variables when /\A\$\S/ - global_variables.each{|gvar| + safe_global_variables.each{|gvar| if gvar.to_s == expr result = eval(gvar.to_s) break false diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 288db814d..1ab859a6b 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -516,6 +516,8 @@ def event type, *args end class Session + include GlobalVariablesHelper + def find_waiting_tc id @th_clients.each{|th, tc| return tc if tc.id == id && tc.waiting? @@ -562,7 +564,7 @@ def process_protocol_request req if ref = @var_map[varid] case ref[0] when :globals - vars = global_variables.sort.map do |name| + vars = safe_global_variables.sort.map do |name| gv = eval(name.to_s) { name: name, @@ -800,7 +802,7 @@ def process_dap args name: 'Global variables', presentationHint: 'globals', variablesReference: 1, # GLOBAL - namedVariables: global_variables.size, + namedVariables: safe_global_variables.size, indexedVariables: 0, expensive: false, }] @@ -887,7 +889,7 @@ def process_dap args message = "Error: Not defined instance variable: #{expr.inspect}" end when /\A\$\S/ - global_variables.each{|gvar| + safe_global_variables.each{|gvar| if gvar.to_s == expr result = eval(gvar.to_s) break false diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 994e6a36f..bfb2c3ee4 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -38,6 +38,13 @@ def skip_location?(loc) end end + module GlobalVariablesHelper + SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze + def safe_global_variables + global_variables.reject{|name| SKIP_GLOBAL_LIST.include? name } + end + end + class ThreadClient def self.current if thc = Thread.current[:DEBUGGER__ThreadClient] @@ -50,6 +57,7 @@ def self.current include Color include SkipPathHelper + include GlobalVariablesHelper attr_reader :thread, :id, :recorder, :check_bp_fulfillment_map @@ -636,9 +644,8 @@ def show_consts pat, expr = nil, only_self: false end end - SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze def show_globals pat - global_variables.sort.each{|name| + safe_global_variables.sort.each{|name| next if SKIP_GLOBAL_LIST.include? name value = eval(name.to_s) From 83031643de9d0df176666edf56e75982e3f8831f Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Wed, 7 Dec 2022 23:46:04 +0900 Subject: [PATCH 050/263] CDP: Refactor the logic in setup method --- lib/debug/server_cdp.rb | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 6d2dacb16..62588de00 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -34,25 +34,26 @@ def setup_chrome addr, uuid loop do res = ws_client.extract_data - case - when res['id'] == 1 && target_info = res.dig('result', 'targetInfos') + case res['id'] + when 1 + target_info = res.dig('result', 'targetInfos') page = target_info.find{|t| t['type'] == 'page'} ws_client.send id: 2, method: 'Target.attachToTarget', params: { targetId: page['targetId'], flatten: true } - when res['id'] == 2 + when 2 s_id = res.dig('result', 'sessionId') # TODO: change id ws_client.send sessionId: s_id, id: 100, method: 'Network.enable' ws_client.send sessionId: s_id, id: 3, method: 'Page.enable' - when res['id'] == 3 + when 3 s_id = res['sessionId'] ws_client.send sessionId: s_id, id: 4, method: 'Page.getFrameTree' - when res['id'] == 4 + when 4 s_id = res['sessionId'] f_id = res.dig('result', 'frameTree', 'frame', 'id') ws_client.send sessionId: s_id, id: 5, @@ -61,17 +62,19 @@ def setup_chrome addr, uuid url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}", frameId: f_id } - when res['method'] == 'Network.webSocketWillSendHandshakeRequest' - s_id = res['sessionId'] - # Display the console by entering ESC key - ws_client.send sessionId: s_id, id: 101, # TODO: change id - method:"Input.dispatchKeyEvent", - params: { - type:"keyDown", - windowsVirtualKeyCode:27 # ESC key - } - when res['id'] == 101 + when 101 break + else + if res['method'] == 'Network.webSocketWillSendHandshakeRequest' + s_id = res['sessionId'] + # Display the console by entering ESC key + ws_client.send sessionId: s_id, id: 101, # TODO: change id + method:"Input.dispatchKeyEvent", + params: { + type:"keyDown", + windowsVirtualKeyCode:27 # ESC key + } + end end end pid From 0030b1d61aee96749cc78bca6c0aec6e128d6be1 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 16 Dec 2022 10:45:53 +0900 Subject: [PATCH 051/263] DAP: cut off `dap_eval` method --- lib/debug/server_dap.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 1ab859a6b..3352603b8 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -737,6 +737,14 @@ def value_inspect obj, short: true end end + def dap_eval b, expr, _context, prompt: '(repl_eval)' + begin + b.eval(expr.to_s, prompt) + rescue Exception => e + e + end + end + def process_dap args # pp tc: self, args: args type = args.shift @@ -874,12 +882,7 @@ def process_dap args case context when 'repl', 'watch' - begin - result = b.eval(expr.to_s, '(DEBUG CONSOLE)') - rescue Exception => e - result = e - end - + result = dap_eval b, expr, context, prompt: '(DEBUG CONSOLE)' when 'hover' case expr when /\A\@\S/ From f42e9c6539641f2fd76f9e2d14e77f0a86808378 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 16 Dec 2022 16:45:12 +0900 Subject: [PATCH 052/263] DAP: show `#dump` when pp'ed string is too long For String objects, show `#dump` when the String object is long enough. However, the length of a String is not correct condition because elimination with `...` is used for long `pp`ed result. This patch shows `#dump` field if `pp'ed_str.end_with?('...')` is true. --- lib/debug/server_dap.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 3352603b8..b6345b5fc 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -723,9 +723,8 @@ def initialize str end class ThreadClient - MAX_LENGTH = 180 - + def value_inspect obj, short: true # TODO: max length should be configuarable? str = DEBUGGER__.safe_inspect obj, short: short, max_length: MAX_LENGTH @@ -847,10 +846,11 @@ def process_dap args } when String vars = [ - variable('#length', obj.length), + variable('#lengthddsfsd', obj.length), variable('#encoding', obj.encoding), ] - vars << variable('#dump', NaiveString.new(obj)) if obj.length > MAX_LENGTH + printed_str = value_inspect(obj) + vars << variable('#dump', NaiveString.new(obj)) if printed_str.end_with?('...') when Class, Module vars << variable('%ancestors', obj.ancestors[1..]) when Range From ef639a2fafc82734e7be52dce69257f7c5bdaf35 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sat, 10 Dec 2022 10:58:36 +0000 Subject: [PATCH 053/263] Add tests for prelude.rb --- test/console/debugger_method_test.rb | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/console/debugger_method_test.rb b/test/console/debugger_method_test.rb index 8cc32198f..1a7ce5406 100644 --- a/test/console/debugger_method_test.rb +++ b/test/console/debugger_method_test.rb @@ -177,4 +177,36 @@ def test_step_in_stops_the_program end end end + + class PreludeTest < ConsoleTestCase + def program + <<~RUBY + 1| require "debug/prelude" + 2| debugger_source = Kernel.method(:debugger).source_location + 3| a = 100 + 4| b = 20 + 5| debugger + 6| + 7| __END__ + RUBY + end + + def test_prelude_defines_debugger_statements + run_ruby(program, options: "-Ilib") do + assert_line_num(5) + type "a + b" + assert_line_text(/120/) + type "c" + end + end + + def test_prelude_doesnt_override_debugger + run_ruby(program, options: "-Ilib -rdebug") do + assert_line_num(5) + type "debugger_source" + assert_line_text(/debug\/session\.rb/) + type "c" + end + end + end end From 06fb3a26f3779e61e17ee397c9b908ab0cf2b653 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sat, 10 Dec 2022 11:03:58 +0000 Subject: [PATCH 054/263] Use stricter check to skip prelude loading Fixes #865 --- lib/debug/prelude.rb | 2 +- test/console/debugger_method_test.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/debug/prelude.rb b/lib/debug/prelude.rb index 67ba18ca2..0f6611963 100644 --- a/lib/debug/prelude.rb +++ b/lib/debug/prelude.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true return if ENV['RUBY_DEBUG_ENABLE'] == '0' -return if defined?(::DEBUGGER__) +return if defined?(::DEBUGGER__::Session) # Put the following line in your login script (e.g. ~/.bash_profile) with modified path: # diff --git a/test/console/debugger_method_test.rb b/test/console/debugger_method_test.rb index 1a7ce5406..458870818 100644 --- a/test/console/debugger_method_test.rb +++ b/test/console/debugger_method_test.rb @@ -208,5 +208,14 @@ def test_prelude_doesnt_override_debugger type "c" end end + + def test_require_config_doesnt_cancel_prelude + run_ruby(program, options: "-Ilib -rdebug/config") do + assert_line_num(5) + type "a + b" + assert_line_text(/120/) + type "c" + end + end end end From 7b7259d7159bc7144c385c1fd6a13e16dd196001 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 22 Dec 2022 20:50:37 +0900 Subject: [PATCH 055/263] skip file For the `` files does not have a file and `absolute_path` is nil, so it is assumed as eval'ed code and `skip_location?` add prefix `!eval:` to the path name. So it also cheks with this prefix too. fix https://github.com/ruby/debug/issues/866 --- lib/debug/thread_client.rb | 2 +- test/console/control_flow_commands_test.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index bfb2c3ee4..cd79a3205 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -29,7 +29,7 @@ def skip_config_skip_path?(path) end def skip_internal_path?(path) - path.start_with?(__dir__) || path.start_with?(' Date: Fri, 23 Dec 2022 02:46:17 +0900 Subject: [PATCH 056/263] DAP: rescue any exception on accessing gvars --- lib/debug/server_dap.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index b6345b5fc..85982c6f1 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -565,7 +565,11 @@ def process_protocol_request req case ref[0] when :globals vars = safe_global_variables.sort.map do |name| - gv = eval(name.to_s) + begin + gv = eval(name.to_s) + rescue Exception => e + gv = e.inspect + end { name: name, value: gv.inspect, From 74255f18edbb4808807284a7b64a2ac81d54fdc8 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 23 Dec 2022 02:51:50 +0900 Subject: [PATCH 057/263] DAP: allow custom request extension --- lib/debug/server_dap.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 85982c6f1..d21e14944 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -452,7 +452,11 @@ def process @q_msg << req else - raise "Unknown request: #{req.inspect}" + if respond_to? mid = "request_#{req['command']}" + send mid, req + else + raise "Unknown request: #{req.inspect}" + end end end ensure From ab985c7b2013266e36c59f66996752f6e8b5f381 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 23 Dec 2022 03:08:32 +0900 Subject: [PATCH 058/263] v1.7.1 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index df6c80e4a..05fad09db 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.7.0" + VERSION = "1.7.1" end From 0fcfc28acae33ec1c08068fb7c33703cfa681fa7 Mon Sep 17 00:00:00 2001 From: TSUYUSATO Kitsune Date: Wed, 28 Dec 2022 08:19:32 +0900 Subject: [PATCH 059/263] Add missing close backquote (#879) --- README.md | 4 ++-- lib/debug/session.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 243c3acbc..4a6a7f600 100644 --- a/README.md +++ b/README.md @@ -563,9 +563,9 @@ The `<...>` notation means the argument. * `u[ntil]` * Similar to `next` command, but only stop later lines or the end of the current frame. * Similar to gdb's `advance` command. -* `u[ntil] <[file:]line> +* `u[ntil] <[file:]line>` * Run til the program reaches given location or the end of the current frame. -* `u[ntil] +* `u[ntil] ` * Run til the program invokes a method ``. `` can be a regexp with `/name/`. * `c` or `cont` or `continue` * Resume the program. diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 1402d554a..78bcce0de 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -480,9 +480,9 @@ def register_default_command # * `u[ntil]` # * Similar to `next` command, but only stop later lines or the end of the current frame. # * Similar to gdb's `advance` command. - # * `u[ntil] <[file:]line> + # * `u[ntil] <[file:]line>` # * Run til the program reaches given location or the end of the current frame. - # * `u[ntil] + # * `u[ntil] ` # * Run til the program invokes a method ``. `` can be a regexp with `/name/`. register_command 'u', 'until', repeat: true, From d7bf3b2e4502eb0f07a67f00e5fce5a0d661189e Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Mon, 30 Jan 2023 18:10:15 +0900 Subject: [PATCH 060/263] Support the new message format of NameError in Ruby 3.3 https://bugs.ruby-lang.org/issues/18285#note-38 ``` old: undefined local variable or method `foo' for main:Object new: undefined local variable or method `foo' for main ``` --- test/console/debugger_local_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/console/debugger_local_test.rb b/test/console/debugger_local_test.rb index 08e7d73ac..14332fba9 100644 --- a/test/console/debugger_local_test.rb +++ b/test/console/debugger_local_test.rb @@ -34,7 +34,7 @@ def test_raised_is_accessible_from_repl type "catch Exception" type "c" type "_raised" - assert_line_text(/undefined local variable or method `foo' for main:Object/) + assert_line_text(/undefined local variable or method `foo' for main/) type "c" end end @@ -43,7 +43,7 @@ def test_raised_is_accessible_from_command debug_code(program) do type "catch Exception pre: p _raised" type "c" - assert_line_text(/undefined local variable or method `foo' for main:Object/) + assert_line_text(/undefined local variable or method `foo' for main/) type "c" end end @@ -96,7 +96,7 @@ def test_raised_doesnt_leak_to_program_binding # stops for NoMethodError because _raised is not defined in the program type "_raised" - assert_line_text(/undefined local variable or method `_raised' for main:Object/) + assert_line_text(/undefined local variable or method `_raised' for main/) type "c" end end @@ -155,7 +155,7 @@ def test_raised_doesnt_leak_to_program_binding type "c" # stops for NoMethodError because _return is not defined in the program type "_raised" - assert_line_text(/undefined local variable or method `_return' for main:Object/) + assert_line_text(/undefined local variable or method `_return' for main/) type "c" end end From 733dd4b464191e147f00fe767f3c6dcd6ae2c6b9 Mon Sep 17 00:00:00 2001 From: Andy Waite <13400+andyw8@users.noreply.github.com> Date: Sun, 26 Feb 2023 22:38:06 -0500 Subject: [PATCH 061/263] Correct `test_all` task command in Rakefile warning (#908) Co-authored-by: Andy Waite --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 99a5a2a10..1a6747ff4 100644 --- a/Rakefile +++ b/Rakefile @@ -46,7 +46,7 @@ Rake::TestTask.new(:test_protocol) do |t| end task test: 'test_console' do - warn '`rake test` doesn\'t run protocol tests. Use `rake test-all` to test all.' + warn '`rake test` doesn\'t run protocol tests. Use `rake test_all` to test all.' end task test_all: [:test_console, :test_protocol] From 5931c4f7aa5142674593df1b12e4d182879c8710 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 3 Mar 2023 10:50:02 +0900 Subject: [PATCH 062/263] DAP: use Object#__send__ to avoid name conflicts --- lib/debug/server_dap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index d21e14944..f883ab5c9 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -453,7 +453,7 @@ def process else if respond_to? mid = "request_#{req['command']}" - send mid, req + __send__ mid, req else raise "Unknown request: #{req.inspect}" end From 411d7e623fc834e60c0bdb0d4e7be70cb1ad9358 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 5 Mar 2023 02:05:51 +0900 Subject: [PATCH 063/263] DAP: allow custom request extension in Session class --- lib/debug/server_dap.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index f883ab5c9..8dedcdc7a 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -651,7 +651,11 @@ def process_protocol_request req fail_response req end else - raise "Unknown DAP request: #{req.inspect}" + if respond_to? mid = "request_#{req['command']}" + __send__ mid, req + else + raise "Unknown request: #{req.inspect}" + end end end From bd9a3bec9356b1f2f82cb11ed9571bc2c4f02971 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 6 Mar 2023 17:14:49 +0900 Subject: [PATCH 064/263] Fix bug that "trace line" does not work after stopping trace once --- lib/debug/session.rb | 2 +- lib/debug/tracer.rb | 4 ++++ test/console/trace_test.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 78bcce0de..68bcbcecd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1524,7 +1524,7 @@ def add_iseq_breakpoint iseq, **kw # tracers def add_tracer tracer - if @tracers.has_key? tracer.key + if @tracers[tracer.key]&.enabled? tracer.disable @ui.puts "Duplicated tracer: #{tracer}" else diff --git a/lib/debug/tracer.rb b/lib/debug/tracer.rb index 09da6dd97..fbbbac108 100644 --- a/lib/debug/tracer.rb +++ b/lib/debug/tracer.rb @@ -54,6 +54,10 @@ def disable @tracer.disable end + def enabled? + @tracer.enabled? + end + def description nil end diff --git a/test/console/trace_test.rb b/test/console/trace_test.rb index e75186d2f..71629e797 100644 --- a/test/console/trace_test.rb +++ b/test/console/trace_test.rb @@ -532,5 +532,31 @@ def test_tracer_prints_correct_method_receiving_messages end end end + + class TraceOnAfterStoppingOnceTest < ConsoleTestCase + def program + <<~RUBY + 1| a=1 + 2| + 3| b=1 + 4| + 5| c=1 + 6| p a + RUBY + end + + def test_1656237686 + debug_code(program) do + type 'trace line' + type 'trace off' + type 'trace line' + type 'b 5' + type 'c' + assert_line_num 5 + assert_line_text(/DEBUGGER \(trace\/line\)/) + type 'kill!' + end + end + end end end From 28b1197b7ef6edb5213fb45d8090d2367ccb6415 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Thu, 2 Mar 2023 10:39:19 -0800 Subject: [PATCH 065/263] Increase timeout in debug_code --- test/support/console_test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 61b87095a..081b3f335 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -86,7 +86,7 @@ def create_message fail_msg, test_info end def debug_code(program, remote: true, &test_steps) - Timeout.timeout(30) do + Timeout.timeout(60) do prepare_test_environment(program, test_steps) do if remote && !NO_REMOTE && MULTITHREADED_TEST begin From 2b418df1c46d35cd7dda40e55eab357bbe4e95f7 Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Wed, 22 Feb 2023 15:55:19 -0500 Subject: [PATCH 066/263] Fix warning about unused variable --- test/console/backtrace_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index ba0fe85c0..52b1238a1 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -136,7 +136,7 @@ def bar omit "Skip test with load files. Cannot create files in HOME directory." end - file = File.open(foo_path, 'w+') { |f| f.write(foo_file) } + File.open(foo_path, 'w+') { |f| f.write(foo_file) } debug_code(program) do type 'c' type 'bt' From 003526b1cf06c51b7db75900b24b888e58cf6fe4 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 10 Feb 2023 13:19:53 -0800 Subject: [PATCH 067/263] Avoid memberless Struct Related to Ruby bug 19416. --- test/console/color_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/console/color_test.rb b/test/console/color_test.rb index 65600c253..8f62dce45 100644 --- a/test/console/color_test.rb +++ b/test/console/color_test.rb @@ -94,7 +94,7 @@ def test_colorize_does_not_color_string_if_do_not_use_colorize CONFIG[:no_color] = nil end - SESSION_class = Struct.new('SESSION') + SESSION_class = Struct.new('SESSION', :a) private From 13fc7774f9aaaad79c4739577637909bb54343cb Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Mon, 6 Feb 2023 21:10:43 +0000 Subject: [PATCH 068/263] Remove redundant raw detach test The test's subject is the `disconnect` request with `restart: false, terminateDebuggee: ` arguments, which has been covered by the tests in `disconnect_dap_test.rb`. So this test case has become obsolete. Co-authored-by: Andy Waite <13400+andyw8@users.noreply.github.com> --- test/protocol/detach_raw_dap_test.rb | 555 --------------------------- 1 file changed, 555 deletions(-) delete mode 100644 test/protocol/detach_raw_dap_test.rb diff --git a/test/protocol/detach_raw_dap_test.rb b/test/protocol/detach_raw_dap_test.rb deleted file mode 100644 index 03406af9e..000000000 --- a/test/protocol/detach_raw_dap_test.rb +++ /dev/null @@ -1,555 +0,0 @@ -# frozen_string_literal: true - -require_relative '../support/protocol_test_case' - -module DEBUGGER__ - - class DetachTest1639218122 < ProtocolTestCase - PROGRAM = <<~RUBY - 1| module Foo - 2| class Bar - 3| def self.a - 4| "hello" - 5| end - 6| end - 7| loop do - 8| b = 1 - 9| end - 10| Bar.a - 11| bar = Bar.new - 12| end - RUBY - - def test_1657544386 - run_dap_scenario PROGRAM do - [ - *INITIALIZE_DAP_MSGS, - { - seq: 7, - type: "event", - event: "stopped", - body: { - reason: "pause", - threadId: 1, - allThreadsStopped: true - } - }, - { - seq: 6, - command: "threads", - type: "request" - }, - { - seq: 8, - type: "response", - command: "threads", - request_seq: 6, - success: true, - message: "Success", - body: { - threads: [ - { - id: 1, - name: /#1 .*/ - } - ] - } - }, - { - seq: 7, - command: "threads", - type: "request" - }, - { - seq: 9, - type: "response", - command: "threads", - request_seq: 7, - success: true, - message: "Success", - body: { - threads: [ - { - id: 1, - name: /#1 .*/ - } - ] - } - }, - { - seq: 8, - command: "stackTrace", - arguments: { - threadId: 1, - startFrame: 0, - levels: 20 - }, - type: "request" - }, - { - seq: 10, - type: "response", - command: "stackTrace", - request_seq: 8, - success: true, - message: "Success", - body: { - stackFrames: [ - { - id: 1, - name: "
", - line: 1, - column: 1, - source: { - name: /#{File.basename temp_file_path}/, - path: /#{temp_file_path}/, - sourceReference: 0 - } - } - ], - totalFrames: 1 - } - }, - { - seq: 9, - command: "scopes", - arguments: { - frameId: 1 - }, - type: "request" - }, - { - seq: 11, - type: "response", - command: "scopes", - request_seq: 9, - success: true, - message: "Success", - body: { - scopes: [ - { - name: "Local variables", - presentationHint: "locals", - namedVariables: /\d+/, - indexedVariables: 0, - expensive: false, - variablesReference: 2 - }, - { - name: "Global variables", - presentationHint: "globals", - variablesReference: 1, - namedVariables: /\d+/, - indexedVariables: 0, - expensive: false - } - ] - } - }, - { - seq: 10, - command: "variables", - arguments: { - variablesReference: 2 - }, - type: "request" - }, - { - seq: 12, - type: "response", - command: "variables", - request_seq: 10, - success: true, - message: "Success", - body: { - variables: [ - { - name: "%self", - value: "main", - type: "Object", - variablesReference: 3, - indexedVariables: 0, - namedVariables: /\d+/ - } - ] - } - }, - { - seq: 11, - command: "disconnect", - arguments: { - restart: false, - terminateDebuggee: false - }, - type: "request" - }, - { - seq: 13, - type: "response", - command: "disconnect", - request_seq: 11, - success: true, - message: "Success" - }, - { - seq: 1, - command: "initialize", - arguments: { - clientID: "vscode", - clientName: "Visual Studio Code", - adapterID: "rdbg", - pathFormat: "path", - linesStartAt1: true, - columnsStartAt1: true, - supportsVariableType: true, - supportsVariablePaging: true, - supportsRunInTerminalRequest: true, - locale: "en-us", - supportsProgressReporting: true, - supportsInvalidatedEvent: true, - supportsMemoryReferences: true - }, - type: "request" - }, - { - seq: 1, - type: "response", - command: "initialize", - request_seq: 1, - success: true, - message: "Success", - body: { - supportsConfigurationDoneRequest: true, - supportsFunctionBreakpoints: true, - supportsConditionalBreakpoints: true, - supportTerminateDebuggee: true, - supportsTerminateRequest: true, - exceptionBreakpointFilters: [ - { - filter: "any", - label: "rescue any exception", - supportsCondition: true - }, - { - filter: "RuntimeError", - label: "rescue RuntimeError", - supportsCondition: true - } - ], - supportsExceptionFilterOptions: true, - supportsStepBack: true, - supportsEvaluateForHovers: true, - supportsCompletionsRequest: true - } - }, - { - seq: 2, - type: "event", - event: "initialized" - }, - { - seq: 2, - command: "attach", - arguments: { - type: "rdbg", - name: "Attach with rdbg", - request: "attach", - __configurationTarget: 5, - __sessionId: "46523ba0-38c2-4503-aa21-ee7c19a263dd" - }, - type: "request" - }, - { - seq: 3, - type: "response", - command: "attach", - request_seq: 2, - success: true, - message: "Success" - }, - { - seq: 3, - command: "setFunctionBreakpoints", - arguments: { - breakpoints: [ - - ] - }, - type: "request" - }, - { - seq: 4, - type: "response", - command: "setFunctionBreakpoints", - request_seq: 3, - success: true, - message: "Success" - }, - { - seq: 4, - command: "setExceptionBreakpoints", - arguments: { - filters: [ - - ], - filterOptions: [ - - ] - }, - type: "request" - }, - { - seq: 5, - type: "response", - command: "setExceptionBreakpoints", - request_seq: 4, - success: true, - message: "Success", - body: { - breakpoints: [ - - ] - } - }, - { - seq: 5, - command: "configurationDone", - type: "request" - }, - { - seq: 6, - type: "response", - command: "configurationDone", - request_seq: 5, - success: true, - message: "Success" - }, - { - seq: 6, - command: "threads", - type: "request" - }, - { - seq: 7, - type: "response", - command: "threads", - request_seq: 6, - success: true, - message: "Success", - body: { - threads: [ - { - id: 1, - name: /#1 .*/ - } - ] - } - }, - { - seq: 7, - command: "pause", - arguments: { - threadId: 1 - }, - type: "request" - }, - { - seq: 8, - type: "response", - command: "pause", - request_seq: 7, - success: true, - message: "Success" - }, - { - seq: 9, - type: "event", - event: "stopped", - body: { - reason: "pause", - threadId: 1, - allThreadsStopped: true - } - }, - { - seq: 8, - command: "threads", - type: "request" - }, - { - seq: 10, - type: "response", - command: "threads", - request_seq: 8, - success: true, - message: "Success", - body: { - threads: [ - { - id: 1, - name: /#1 .*/ - } - ] - } - }, - { - seq: 9, - command: "stackTrace", - arguments: { - threadId: 1, - startFrame: 0, - levels: 20 - }, - type: "request" - }, - { - seq: 11, - type: "response", - command: "stackTrace", - request_seq: 9, - success: true, - message: "Success", - body: { - stackFrames: [ - { - id: 2, - name: "block in ", - line: 9, - column: 1, - source: { - name: /#{File.basename temp_file_path}/, - path: /#{temp_file_path}/, - sourceReference: 0 - } - }, - { - id: 3, - name: "[C] Kernel#loop", - line: 7, - column: 1, - source: { - name: /#{File.basename temp_file_path}/, - path: /#{temp_file_path}/, - sourceReference: 0 - } - }, - { - id: 4, - name: "", - line: 7, - column: 1, - source: { - name: /#{File.basename temp_file_path}/, - path: /#{temp_file_path}/, - sourceReference: 0 - } - }, - { - id: 5, - name: "
", - line: 1, - column: 1, - source: { - name: /#{File.basename temp_file_path}/, - path: /#{temp_file_path}/, - sourceReference: 0 - } - } - ], - totalFrames: 4 - } - }, - { - seq: 10, - command: "scopes", - arguments: { - frameId: 2 - }, - type: "request" - }, - { - seq: 12, - type: "response", - command: "scopes", - request_seq: 10, - success: true, - message: "Success", - body: { - scopes: [ - { - name: "Local variables", - presentationHint: "locals", - namedVariables: /\d+/, - indexedVariables: 0, - expensive: false, - variablesReference: 4 - }, - { - name: "Global variables", - presentationHint: "globals", - variablesReference: 1, - namedVariables: /\d+/, - indexedVariables: 0, - expensive: false - } - ] - } - }, - { - seq: 11, - command: "variables", - arguments: { - variablesReference: 4 - }, - type: "request" - }, - { - seq: 13, - type: "response", - command: "variables", - request_seq: 11, - success: true, - message: "Success", - body: { - variables: [ - { - name: "%self", - value: "Foo", - type: "Module", - variablesReference: 5, - indexedVariables: 0, - namedVariables: /\d+/ - }, - { - name: "b", - value: "1", - type: "Integer", - variablesReference: 6, - indexedVariables: 0, - namedVariables: /\d+/ - }, - { - name: "bar", - value: "nil", - type: "NilClass", - variablesReference: 7, - indexedVariables: 0, - namedVariables: /\d+/ - } - ] - } - }, - { - seq: 12, - command: "disconnect", - arguments: { - restart: false, - terminateDebuggee: true - }, - type: "request" - } - ] - end - end - end -end From 9bf6bd341e6a3f0ce5285a3e5a961dcc830cc511 Mon Sep 17 00:00:00 2001 From: Mau Magnaguagno Date: Tue, 31 Jan 2023 09:15:59 -0300 Subject: [PATCH 069/263] Always propagate keyword arguments in WebSocketServer --- lib/debug/server_cdp.rb | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 62588de00..d23f9d649 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -450,11 +450,7 @@ def extract_data end def send_response req, **res - if res.empty? - @ws_server.send id: req['id'], result: {} - else - @ws_server.send id: req['id'], result: res - end + @ws_server.send id: req['id'], result: res end def send_fail_response req, **res @@ -462,11 +458,7 @@ def send_fail_response req, **res end def send_event method, **params - if params.empty? - @ws_server.send method: method, params: {} - else - @ws_server.send method: method, params: params - end + @ws_server.send method: method, params: params end INVALID_REQUEST = -32600 @@ -681,11 +673,7 @@ def respond_fail req, **result end def fire_event event, **result - if result.empty? - send_event event - else - send_event event, **result - end + send_event event, **result end def sock skip: false From ffb5a98a8223da6b5f446e82a7df644b4817028e Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Wed, 22 Feb 2023 09:21:22 -0500 Subject: [PATCH 070/263] Fix `::Process::daemon` patch As discussed here: https://github.com/ruby/debug/commit/699a31e1adfcf51cf4f6f9e84f862e45072f83b4#r94469355 --- lib/debug/session.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 68bcbcecd..d5b1dbf69 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2438,7 +2438,7 @@ def fork(&given_block) end module DaemonInterceptor - def daemon + def daemon(*args) return super unless defined?(SESSION) && SESSION.active? _, child_hook = __fork_setup_for_debugger(:child) From e2a8b95dc79499778158da9544dcf2406ca556fa Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Wed, 22 Feb 2023 15:50:55 -0500 Subject: [PATCH 071/263] Add test --- test/console/daemon_test.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/console/daemon_test.rb b/test/console/daemon_test.rb index 87049b405..9acd3fe2c 100644 --- a/test/console/daemon_test.rb +++ b/test/console/daemon_test.rb @@ -28,5 +28,26 @@ def test_daemon type 'c' end end + + def program_with_daemon_arguments + <<~'RUBY' + 1| trap(:HUP, 'IGNORE') + 2| puts 'Daemon starting' + 3| Process.daemon(false, false) + 4| puts 'Daemon started' + RUBY + end + + def test_daemon_patch + debug_code program_with_daemon_arguments, remote: :remote_only do + type 'b 3' + type 'c' + assert_line_num 3 + type 'b 4' + type 'c' + assert_line_num 4 + type 'c' + end + end end end From cb371de2539b5d620dfc918b330b7cee765e5dfc Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Wed, 22 Feb 2023 16:10:54 -0500 Subject: [PATCH 072/263] Use local variables --- test/console/daemon_test.rb | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/test/console/daemon_test.rb b/test/console/daemon_test.rb index 9acd3fe2c..0c98435bb 100644 --- a/test/console/daemon_test.rb +++ b/test/console/daemon_test.rb @@ -4,19 +4,18 @@ module DEBUGGER__ class DaemonTest < ConsoleTestCase - def program + + def test_daemon # Ignore SIGHUP since the test debuggee receives SIGHUP after Process.daemon. # When manualy debugging a daemon, it doesn't receive SIGHUP. # I don't know why. - <<~'RUBY' + program = <<~'RUBY' 1| trap(:HUP, 'IGNORE') 2| puts 'Daemon starting' 3| Process.daemon 4| puts 'Daemon started' RUBY - end - def test_daemon # The program can't be debugged locally since the parent process exits when Process.daemon is called. debug_code program, remote: :remote_only do type 'b 3' @@ -29,17 +28,15 @@ def test_daemon end end - def program_with_daemon_arguments - <<~'RUBY' + def test_daemon_patch + program = <<~'RUBY' 1| trap(:HUP, 'IGNORE') 2| puts 'Daemon starting' 3| Process.daemon(false, false) 4| puts 'Daemon started' RUBY - end - def test_daemon_patch - debug_code program_with_daemon_arguments, remote: :remote_only do + debug_code program, remote: :remote_only do type 'b 3' type 'c' assert_line_num 3 From a12928583eda2d12527f62480ce113da704ee28a Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Tue, 17 Jan 2023 15:38:46 -0300 Subject: [PATCH 073/263] Add test for info consts with an expression Co-authored-by: Andy Waite --- test/console/info_test.rb | 81 ++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/test/console/info_test.rb b/test/console/info_test.rb index ae72f42af..40b775967 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -127,29 +127,36 @@ class InfoConstantTest < ConsoleTestCase def program <<~RUBY 1| - 1| class C0 - 2| C0_CONST1 = -1 - 3| C0_CONST2 = -2 - 4| end - 5| - 6| class D - 7| D_CONST1 = 1 - 8| D_CONST2 = 1 - 9| class C1 < C0 - 10| CONST1 = 1 - 11| CONST2 = 2 - 12| l1 = 10 - 13| l2 = 20 - 14| @i1 = 100 - 15| @i2 = 200 - 16| - 17| def foo - 18| :foo - 19| end - 20| end - 21| end - 22| - 23| D::C1.new.foo + 2| class C0 + 3| C0_CONST1 = -1 + 4| C0_CONST2 = -2 + 5| end + 6| + 7| class D + 8| D_CONST1 = 1 + 9| D_CONST2 = 1 + 10| class C1 < C0 + 11| CONST1 = 1 + 12| CONST2 = 2 + 13| l1 = 10 + 14| l2 = 20 + 15| @i1 = 100 + 16| @i2 = 200 + 17| + 18| def foo + 19| :foo + 20| end + 21| end + 22| end + 23| + 24| class E + 25| E_CONST1 = C0 + 26| def self.foo + 27| D + 28| end + 29| end + 30| + 31| D::C1.new.foo RUBY end @@ -213,6 +220,34 @@ def test_info_constant_twice type 'c' end end + + def test_info_constant_with_expression + debug_code(program) do + type "b 31" + type "c" + assert_line_num 31 + + type "info constants E" + assert_line_text([ + /E_CONST1 = C0/, + ]) + + type "info constants E.foo" + assert_line_text([ + /C1 = D::C1/, + /D_CONST1 = 1/, + /D_CONST2 = 1/, + ]) + + type "info constants E::E_CONST1" + assert_line_text([ + /C0_CONST1 = -1/, + /C0_CONST2 = -2/, + ]) + + type "c" + end + end end class InfoIvarsTest < ConsoleTestCase From 0c6a32e71004e9a2b29207038e2870712d4ce50e Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 9 Jan 2023 23:35:29 +0900 Subject: [PATCH 074/263] Fix typo in README --- README.md | 2 +- misc/README.md.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a6a7f600..5e7b72b27 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ New debug.rb has several advantages: * Support threads (almost done) and ractors (TODO). * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing. * Show parameters on backtrace command. - * Support recording & reply debugging. + * Support recording & replay debugging. # Installation diff --git a/misc/README.md.erb b/misc/README.md.erb index 5fa685b35..5778e5a90 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -26,7 +26,7 @@ New debug.rb has several advantages: * Support threads (almost done) and ractors (TODO). * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing. * Show parameters on backtrace command. - * Support recording & reply debugging. + * Support recording & replay debugging. # Installation From cbc79cd274c8c26dd2388be8717487b422157881 Mon Sep 17 00:00:00 2001 From: yamashush <38120991+yamashush@users.noreply.github.com> Date: Mon, 2 Jan 2023 15:59:16 +0900 Subject: [PATCH 075/263] :arrow_up: Update ci ruby versions --- .github/workflows/ruby-macos.yaml | 2 +- .github/workflows/ruby.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 1d1fa2624..f3ef96c53 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['3.1', 'head'] + ruby-version: ['3.2', 'head'] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 66172942a..2b3477d0f 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head', 'debug'] + ruby-version: ['2.7', '3.0', '3.1', '3.2', 'head', 'debug'] steps: - uses: actions/checkout@v3 From bc8b5b67a9badfb8a901077aa38f8665001bf02f Mon Sep 17 00:00:00 2001 From: yamashush <38120991+yamashush@users.noreply.github.com> Date: Sat, 7 Jan 2023 10:12:21 +0900 Subject: [PATCH 076/263] :rewind: Revert Ruby 2.6 --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 2b3477d0f..dd6bdc64c 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.7', '3.0', '3.1', '3.2', 'head', 'debug'] + ruby-version: ['2.6, '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] steps: - uses: actions/checkout@v3 From f7e57912020224aecf5c2ed64176833ac0e4c5db Mon Sep 17 00:00:00 2001 From: yamashush <38120991+yamashush@users.noreply.github.com> Date: Sat, 7 Jan 2023 10:13:22 +0900 Subject: [PATCH 077/263] :pencil2: Fix typo --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index dd6bdc64c..5dcc41426 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6, '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] + ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] steps: - uses: actions/checkout@v3 From bd8678c0d8c60c4357e98704a21ca509934e064d Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 9 Jan 2023 22:21:32 +0900 Subject: [PATCH 078/263] CDP: Support evaluating expression on non-current frame --- lib/debug/server_cdp.rb | 2 +- test/protocol/eval_test.rb | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index d23f9d649..66843e4ca 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -1059,7 +1059,7 @@ def process_cdp args begin orig_stdout = $stdout $stdout = StringIO.new - result = current_frame.binding.eval(expr.to_s, '(DEBUG CONSOLE)') + result = b.eval(expr.to_s, '(DEBUG CONSOLE)') rescue Exception => e result = e res[:exceptionDetails] = exceptionDetails(e, 'Uncaught') diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index 635ea814e..94ac19dc8 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -24,4 +24,24 @@ def test_eval_evaluates_arithmetic_expressions end end end + + class EvaluateOnSomeFramesTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| a = 2 + 2| def foo + 3| a = 4 + 4| end + 5| foo + RUBY + + def test_eval_evaluates_arithmetic_expressions + run_protocol_scenario PROGRAM do + req_add_breakpoint 4 + req_continue + assert_repl_result({value: '4', type: 'Integer'}, 'a', frame_idx: 0) + assert_repl_result({value: '2', type: 'Integer'}, 'a', frame_idx: 1) + req_terminate_debuggee + end + end + end end From 6f79d2ab2a9d4886ae908dd33a59517ac4873c75 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Tue, 7 Mar 2023 23:50:09 +0900 Subject: [PATCH 079/263] CDP: support reattaching in Chrome DevTools Close #800 --- lib/debug/server_cdp.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 66843e4ca..e3f0bb4f4 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -549,6 +549,9 @@ def process activate_bp bps end send_response req + when 'Debugger.pause' + send_response req + Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid) # breakpoint when 'Debugger.getPossibleBreakpoints' From 66a5035e25cb34ffeac61f0655aeb084aee82180 Mon Sep 17 00:00:00 2001 From: "Jose D. Gomez R" Date: Thu, 9 Feb 2023 22:29:24 +0100 Subject: [PATCH 080/263] Improved stability for chrome debugging - Display the greeting message regardless of the status of invocation of chrome. This allows coming back to the debugger on a new tab when the window process by `UI_CDP.run_new_chrome` is killed. - Handle `Errno::ESRCH` in `UI_CDP.cleanup_reader`. When the process by `UI_CDP.run_new_chrome` is killed, re-killing it breaks your debugging session and in turn the "debugee". --- lib/debug/server.rb | 11 +++++------ lib/debug/server_cdp.rb | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 64bd3bff4..a67922ac1 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -406,14 +406,13 @@ def chrome_setup require_relative 'server_cdp' @uuid = SecureRandom.uuid - unless @chrome_pid = UI_CDP.setup_chrome(@local_addr.inspect_sockaddr, @uuid) - DEBUGGER__.warn <<~EOS - With Chrome browser, type the following URL in the address-bar: + @chrome_pid = UI_CDP.setup_chrome(@local_addr.inspect_sockaddr, @uuid) + DEBUGGER__.warn <<~EOS + With Chrome browser, type the following URL in the address-bar: - devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid} + devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid} - EOS - end + EOS end def accept diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index e3f0bb4f4..f6c63ecf7 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -663,6 +663,7 @@ def deactivate_bp def cleanup_reader super Process.kill :KILL, @chrome_pid if @chrome_pid + rescue Errno::ESRCH # continue if @chrome_pid process is not found end ## Called by the SESSION thread From 465e4dde3e91bcc96ab59e3682415c89ca4875ec Mon Sep 17 00:00:00 2001 From: "Jose D. Gomez R" Date: Fri, 10 Feb 2023 09:23:33 +0100 Subject: [PATCH 081/263] Make `UI_ServerBase#puts` to behave like `STDERR#puts` `UI_ServerBase#greeting` calls `#puts` with no arguments, this breaks reconnections to the debugger. --- lib/debug/server_cdp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index f6c63ecf7..264c5d72e 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -684,7 +684,7 @@ def sock skip: false yield $stderr end - def puts result + def puts result='' # STDERR.puts "puts: #{result}" # send_event 'output', category: 'stderr', output: "PUTS!!: " + result.to_s end From 7a37045098871a89da00641eb59bbca2d89915e2 Mon Sep 17 00:00:00 2001 From: "Jose D. Gomez R" Date: Fri, 10 Feb 2023 13:20:28 +0100 Subject: [PATCH 082/263] Handle not existing $FILENAME in `Session#process_protocol_request` `Session#process_protocol_request` gracefully handles `Errno::ENOENT` when `eval`-ing `$FILENAME`, and it doens't exist. --- lib/debug/server_cdp.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 264c5d72e..7f0c7cd2b 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -748,7 +748,11 @@ def process_protocol_request req request_tc [:cdp, :scope, req, fid] when 'global' vars = safe_global_variables.sort.map do |name| - gv = eval(name.to_s) + begin + gv = eval(name.to_s) + rescue Errno::ENOENT + gv = nil + end prop = { name: name, value: { From 67ea2d495431bc889b241c935b07bc5c5d72525b Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 8 Mar 2023 03:03:58 +0900 Subject: [PATCH 083/263] free terminated ThreadClients fix https://github.com/ruby/debug/issues/899 --- lib/debug/session.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index d5b1dbf69..3ece5aacb 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -128,6 +128,8 @@ def initialize @obj_map = {} # { object_id => ... } for CDP @tp_thread_begin = nil + @tp_thread_end = nil + @commands = {} @unsafe_context = false @@ -169,8 +171,9 @@ def activate ui = nil, on_fork: false @ui = ui if ui @tp_thread_begin&.disable + @tp_thread_end&.disable @tp_thread_begin = nil - + @tp_thread_end = nil @ui.activate self, on_fork: on_fork q = Queue.new @@ -192,6 +195,11 @@ def activate ui = nil, on_fork: false end @tp_thread_begin.enable + @tp_thread_end = TracePoint.new(:thread_end) do |tp| + @th_clients.delete(Thread.current) + end + @tp_thread_end.enable + # session start q << true session_server_main @@ -205,6 +213,7 @@ def deactivate @thread_stopper.disable @tp_load_script.disable @tp_thread_begin.disable + @tp_thread_end.disable @bps.each_value{|bp| bp.disable} @th_clients.each_value{|thc| thc.close} @tracers.values.each{|t| t.disable} @@ -219,11 +228,13 @@ def reset_ui ui # activate new ui @tp_thread_begin.disable + @tp_thread_end.disable @ui.activate self if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread) thc.mark_as_management end @tp_thread_begin.enable + @tp_thread_end.enable end def pop_event From 7b0c07898121bd86ba8bd9f0ac221628c72d7d3c Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 6 Mar 2023 17:05:51 +0900 Subject: [PATCH 084/263] DAP: use Mutex when sending response When debug.gem tries to send response from multiple threads, the socket connection is closed. I confirmed this bug when using custom request from vscode-rdbg --- lib/debug/server_dap.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 8dedcdc7a..8947d5697 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -125,6 +125,7 @@ def self.local_fs_map_set map def dap_setup bytes CONFIG.set_config no_color: true @seq = 0 + @send_lock = Mutex.new case self when UI_UnixDomainServer @@ -212,9 +213,13 @@ def send **kw if sock = @sock kw[:seq] = @seq += 1 str = JSON.dump(kw) - sock.write "Content-Length: #{str.bytesize}\r\n\r\n#{str}" + @send_lock.synchronize do + sock.write "Content-Length: #{str.bytesize}\r\n\r\n#{str}" + end show_protocol '<', str end + rescue Errno::EPIPE => e + $stderr.puts "#{e.inspect} rescued during sending message" end def send_response req, success: true, message: nil, **kw From a236601406c211f591a58f219f8841b3e2a101b7 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Thu, 9 Mar 2023 00:40:23 +0900 Subject: [PATCH 085/263] Make sure to fail when remote debuggee does not exit after scenarios Because Errno::EPIPE is rescued while sending message to socket, protocol_test_case_test.rb does not pass. protocol_test_case_test.rb had been passed because ReaderThreadError was occurred and the debuggee process was still alive. Here is a scenario. After closing socket, terminated event was sent. However socket was closed, so debuggee process raised Errno::EPIPE and debugggee process was still alive. The test framework detected the status and failed. Thus I fixed so that the test framework does not kill the debuggee process unexpectedly. --- test/support/protocol_test_case.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index a2c3414e3..7b06ad529 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -335,12 +335,13 @@ def execute_dap_scenario scenario attach_to_dap_server scenario.call ensure - @reader_thread&.kill - @sock&.close kill_remote_debuggee test_info if name = test_info.failed_process flunk create_protocol_message "Expected the debuggee program to finish" end + # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. + @reader_thread&.kill + @sock&.close end def execute_cdp_scenario_ scenario @@ -365,12 +366,13 @@ def execute_cdp_scenario_ scenario @crt_frames = res.dig(:params, :callFrames) scenario.call ensure - @reader_thread&.kill - @web_sock&.close kill_remote_debuggee test_info if name = test_info.failed_process flunk create_protocol_message "Expected the debuggee program to finish" end + # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. + @reader_thread&.kill + @web_sock&.close end def execute_cdp_scenario scenario From ad8aeca7ffa64e0b622037957a2724ffa5bd8cb9 Mon Sep 17 00:00:00 2001 From: Mau Magnaguagno Date: Tue, 7 Mar 2023 15:35:59 -0300 Subject: [PATCH 086/263] Alias Session send methods in WebSocketServer Methods ``respond``, ``respond_fail`` and ``fire_event`` can be aliased to ``send_response``, ``send_fail_response`` and ``send_event``, respectively. --- lib/debug/server_cdp.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 7f0c7cd2b..75df47bfe 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -668,17 +668,9 @@ def cleanup_reader ## Called by the SESSION thread - def respond req, **result - send_response req, **result - end - - def respond_fail req, **result - send_fail_response req, **result - end - - def fire_event event, **result - send_event event, **result - end + alias respond send_response + alias respond_fail send_fail_response + alias fire_event send_event def sock skip: false yield $stderr From 5b29bd785b31048c9c2032ed997d1cb6ae3ac73a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 9 Mar 2023 11:26:36 +0900 Subject: [PATCH 087/263] Fix timing bug on session_server creation `@session_server` should be assigned at first. `@session_server = Thread.current` in the session thread does not work because the creator thread can access to `@session_server` before it. --- lib/debug/session.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3ece5aacb..3f9541636 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -177,7 +177,11 @@ def activate ui = nil, on_fork: false @ui.activate self, on_fork: on_fork q = Queue.new + first_q = Queue.new @session_server = Thread.new do + # make sure `@session_server` is assigned + first_q.pop; first_q = nil + Thread.current.name = 'DEBUGGER__::SESSION@server' Thread.current.abort_on_exception = true @@ -204,6 +208,7 @@ def activate ui = nil, on_fork: false q << true session_server_main end + first_q << :ok q.pop end From f1f92116267c1afb50386e82a5d3828c15f9b48f Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Thu, 9 Mar 2023 12:14:36 -0500 Subject: [PATCH 088/263] Fix useless assignments Found by running `rubocop --only=Lint/UselessAssignment` --- lib/debug/server_cdp.rb | 1 - lib/debug/server_dap.rb | 18 +++++++++--------- lib/debug/source_repository.rb | 2 +- test/support/protocol_test_case.rb | 5 ++--- test/support/test_case.rb | 4 ++-- test/tool/test_builder.rb | 4 ++-- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 75df47bfe..6eb6fd678 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -98,7 +98,6 @@ def run_new_chrome candidates = ['C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'] path = get_chrome_path candidates end - uuid = SecureRandom.uuid # The path is based on https://github.com/sindresorhus/open/blob/v8.4.0/index.js#L128. stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell") tf = Tempfile.create(['debug-', '.txt']) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 8947d5697..0a2afa71c 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -251,17 +251,17 @@ class RetryBecauseCantRead < Exception end def recv_request - r = IO.select([@sock]) + IO.select([@sock]) @session.process_group.sync do raise RetryBecauseCantRead unless IO.select([@sock], nil, nil, 0) - case header = @sock.gets + case @sock.gets when /Content-Length: (\d+)/ b = @sock.read(2) raise b.inspect unless b == "\r\n" - l = @sock.read(s = $1.to_i) + l = @sock.read($1.to_i) show_protocol :>, l JSON.load(l) when nil @@ -551,7 +551,7 @@ def process_protocol_request req when 'stackTrace' tid = req.dig('arguments', 'threadId') - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) request_tc [:dap, :backtrace, req] else fail_response req @@ -560,7 +560,7 @@ def process_protocol_request req frame_id = req.dig('arguments', 'frameId') if @frame_map[frame_id] tid, fid = @frame_map[frame_id] - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) request_tc [:dap, :scopes, req, fid] else fail_response req @@ -596,7 +596,7 @@ def process_protocol_request req frame_id = ref[1] tid, fid = @frame_map[frame_id] - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) request_tc [:dap, :scope, req, fid] else fail_response req @@ -605,7 +605,7 @@ def process_protocol_request req when :variable tid, vid = ref[1], ref[2] - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) request_tc [:dap, :variable, req, vid] else fail_response req @@ -624,7 +624,7 @@ def process_protocol_request req tid, fid = @frame_map[frame_id] expr = req.dig('arguments', 'expression') - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) request_tc [:dap, :evaluate, req, fid, expr, context] else fail_response req @@ -645,7 +645,7 @@ def process_protocol_request req frame_id = req.dig('arguments', 'frameId') tid, fid = @frame_map[frame_id] - if tc = find_waiting_tc(tid) + if find_waiting_tc(tid) text = req.dig('arguments', 'text') line = req.dig('arguments', 'line') if col = req.dig('arguments', 'column') diff --git a/lib/debug/source_repository.rb b/lib/debug/source_repository.rb index 27cf98878..b2ef28409 100644 --- a/lib/debug/source_repository.rb +++ b/lib/debug/source_repository.rb @@ -49,7 +49,7 @@ def orig_src iseq lines = iseq.script_lines&.map(&:chomp) line = iseq.first_line if line > 1 - lines = [*([''] * (line - 1)), *lines] + [*([''] * (line - 1)), *lines] else lines end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 7b06ad529..1deb5cd98 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -336,7 +336,7 @@ def execute_dap_scenario scenario scenario.call ensure kill_remote_debuggee test_info - if name = test_info.failed_process + if test_info.failed_process flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @@ -367,7 +367,7 @@ def execute_cdp_scenario_ scenario scenario.call ensure kill_remote_debuggee test_info - if name = test_info.failed_process + if test_info.failed_process flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @@ -1067,4 +1067,3 @@ def parse_ k, v end end end - diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5f8ed7a1b..976ad30fc 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -223,11 +223,11 @@ def get_request host, port, path sock.print "GET #{path} HTTP/1.1\r\n" sock.close_write loop do - case header = sock.gets + case sock.gets when /Content-Length: (\d+)/ b = sock.read(2) raise b.inspect unless b == "\r\n" - + l = sock.read $1.to_i return JSON.parse l, symbolize_names: true end diff --git a/test/tool/test_builder.rb b/test/tool/test_builder.rb index 5553ea599..be48a5514 100644 --- a/test/tool/test_builder.rb +++ b/test/tool/test_builder.rb @@ -477,7 +477,7 @@ def activate_debugger when /\[\>\]\s(.*)/ begin req = JSON.parse $1 - rescue JSON::ParserError => e + rescue JSON::ParserError $stderr.print data next end @@ -504,7 +504,7 @@ def activate_debugger when /\[\<\]\s(.*)/ begin res = JSON.parse $1 - rescue JSON::ParserError => e + rescue JSON::ParserError $stderr.print data next end From a9bec2540e68088be9d0ffcddb7d6bc0cf03929b Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 9 Mar 2023 21:11:32 +0800 Subject: [PATCH 089/263] Remove Tracer#puts as it's not used --- lib/debug/tracer.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/debug/tracer.rb b/lib/debug/tracer.rb index fbbbac108..49c6923c1 100644 --- a/lib/debug/tracer.rb +++ b/lib/debug/tracer.rb @@ -89,11 +89,6 @@ def out tp, msg = nil, depth = caller.size - 1 end end - def puts msg - @output.puts msg - @output.flush - end - def minfo tp return "block{}" if tp.event == :b_call From c258ee0f2832a64e2e83814416289a6e0f7f4d06 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 9 Mar 2023 18:07:30 +0800 Subject: [PATCH 090/263] Avoid raising debuggee not finished error if assertions failed When assertions failed, we should let the AssertionFailedError surface and not calling flunk so we can get correct failure messages. --- test/support/protocol_test_case.rb | 10 +++++++-- test/support/protocol_test_case_test.rb | 27 +++++++++++++++++++------ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 1deb5cd98..acdcae65c 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -334,9 +334,12 @@ def execute_dap_scenario scenario attach_to_dap_server scenario.call + rescue Test::Unit::AssertionFailedError => e + is_assertion_failure = true + raise e ensure kill_remote_debuggee test_info - if test_info.failed_process + if test_info.failed_process && !is_assertion_failure flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @@ -365,9 +368,12 @@ def execute_cdp_scenario_ scenario res = find_response :method, 'Debugger.paused', 'C e + is_assertion_failure = true + raise e ensure kill_remote_debuggee test_info - if test_info.failed_process + if test_info.failed_process && !is_assertion_failure flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. diff --git a/test/support/protocol_test_case_test.rb b/test/support/protocol_test_case_test.rb index d9e687f9b..4c132b8ac 100644 --- a/test/support/protocol_test_case_test.rb +++ b/test/support/protocol_test_case_test.rb @@ -3,14 +3,29 @@ require_relative 'protocol_test_case' module DEBUGGER__ - class TestFrameworkTestHOge < ProtocolTestCase - PROGRAM = <<~RUBY - 1| a=1 - RUBY - + class TestProtocolTestCase < ProtocolTestCase def test_the_test_fails_when_debuggee_doesnt_exit + program = <<~RUBY + 1| a=1 + RUBY + assert_fail_assertion do - run_protocol_scenario PROGRAM do + run_protocol_scenario program do + end + end + end + + def test_the_assertion_failure_takes_presedence_over_debuggee_not_exiting + program = <<~RUBY + 1| a = 2 + 2| b = 3 + RUBY + + assert_raise_message(/<\"100\"> expected but was/) do + run_protocol_scenario program do + req_add_breakpoint 2 + req_continue + assert_repl_result({value: '100', type: 'Integer'}, 'a') end end end From 64552e2013338f6af03031dceed44494a1591eb1 Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Fri, 10 Mar 2023 13:09:51 -0500 Subject: [PATCH 091/263] Fix test builder --- CONTRIBUTING.md | 4 ++-- test/tool/test_builder.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 22c8bfcf0..68ca46798 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -149,10 +149,10 @@ If the file already exists, **only method** will be added to it. ```ruby # frozen_string_literal: true -require_relative '../support/test_case' +require_relative '../support/console_test_case' module DEBUGGER__ - class FooTest < TestCase + class FooTest < ConsoleTestCase def program <<~RUBY 1| module Foo diff --git a/test/tool/test_builder.rb b/test/tool/test_builder.rb index be48a5514..45fe10843 100644 --- a/test/tool/test_builder.rb +++ b/test/tool/test_builder.rb @@ -157,7 +157,7 @@ def #{@method} def create_scenario_and_program <<-TEST.chomp - class #{@class}#{@current_time} < TestCase + class #{@class}#{@current_time} < ConsoleTestCase def program <<~RUBY #{format_program} From ec4e2f7980ad6c49068a3742fade38ee9e0aa579 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 5 Mar 2023 02:10:38 +0900 Subject: [PATCH 092/263] DAP: allow custom request extension in ThreadClient class --- lib/debug/server_dap.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 0a2afa71c..63b75827a 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -973,7 +973,11 @@ def process_dap args } else - raise "Unknown req: #{args.inspect}" + if respond_to? mid = "request_#{type}" + __send__ mid, req + else + raise "Unknown request: #{args.inspect}" + end end end From e29fabaecde4086020953de56e833bf3b076f7b5 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Tue, 21 Mar 2023 00:31:48 +0900 Subject: [PATCH 093/263] DAP: introduce Rdbg Record Inspector --- lib/debug/server_dap.rb | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 63b75827a..0cc76f337 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -468,6 +468,10 @@ def process send_event :terminated unless @sock.closed? end + def request_rdbgRecordInspector req + @q_msg << req + end + ## called by the SESSION thread def respond req, res @@ -664,6 +668,43 @@ def process_protocol_request req end end + def request_rdbgRecordInspector req + cmd = req.dig('arguments', 'command') + case cmd + when 'enable' + request_tc [:record, :on] + @ui.respond req, {} + when 'disable' + request_tc [:record, :off] + @ui.respond req, {} + when 'step' + tid = req.dig('arguments', 'threadId') + count = req.dig('arguments', 'count') + if tc = find_waiting_tc(tid) + tc << [:step, :in, count] + else + fail_response req + end + when 'stepBack' + tid = req.dig('arguments', 'threadId') + count = req.dig('arguments', 'count') + if tc = find_waiting_tc(tid) + tc << [:step, :back, count] + else + fail_response req + end + when 'collect' + tid = req.dig('arguments', 'threadId') + if tc = find_waiting_tc(tid) + tc << [:dap, :rdbgRecordInspector, req] + else + fail_response req + end + else + raise "Unknown command #{cmd}" + end + end + def dap_event args # puts({dap_event: args}.inspect) type, req, result = args @@ -711,6 +752,10 @@ def dap_event args end when :completions @ui.respond req, result + + # custom request + when :rdbgRecordInspector + @ui.respond req, result else raise "unsupported: #{args.inspect}" end @@ -981,6 +1026,26 @@ def process_dap args end end + def request_rdbgRecordInspector req + logs = [] + log_index = nil + unless @recorder.nil? + log_index = @recorder.log_index + @recorder.log.each{|frames| + crt_frame = frames[0] + logs << { + name: crt_frame.name, + location: { + path: crt_frame.location.path, + line: crt_frame.location.lineno, + }, + depth: crt_frame.frame_depth + } + } + end + event! :dap_result, :rdbgRecordInspector, req, logs: logs, stoppedIndex: log_index + end + def search_const b, expr cs = expr.delete_prefix('::').split('::') [Object, *b.eval('::Module.nesting')].reverse_each{|mod| From 49e37f95a50ce46b5dc9198e69604f93ff6d869a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 22 Mar 2023 11:27:43 +0900 Subject: [PATCH 094/263] Revert "DAP: introduce Rdbg Record Inspector" This reverts commit e29fabaecde4086020953de56e833bf3b076f7b5. --- lib/debug/server_dap.rb | 65 ----------------------------------------- 1 file changed, 65 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 0cc76f337..63b75827a 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -468,10 +468,6 @@ def process send_event :terminated unless @sock.closed? end - def request_rdbgRecordInspector req - @q_msg << req - end - ## called by the SESSION thread def respond req, res @@ -668,43 +664,6 @@ def process_protocol_request req end end - def request_rdbgRecordInspector req - cmd = req.dig('arguments', 'command') - case cmd - when 'enable' - request_tc [:record, :on] - @ui.respond req, {} - when 'disable' - request_tc [:record, :off] - @ui.respond req, {} - when 'step' - tid = req.dig('arguments', 'threadId') - count = req.dig('arguments', 'count') - if tc = find_waiting_tc(tid) - tc << [:step, :in, count] - else - fail_response req - end - when 'stepBack' - tid = req.dig('arguments', 'threadId') - count = req.dig('arguments', 'count') - if tc = find_waiting_tc(tid) - tc << [:step, :back, count] - else - fail_response req - end - when 'collect' - tid = req.dig('arguments', 'threadId') - if tc = find_waiting_tc(tid) - tc << [:dap, :rdbgRecordInspector, req] - else - fail_response req - end - else - raise "Unknown command #{cmd}" - end - end - def dap_event args # puts({dap_event: args}.inspect) type, req, result = args @@ -752,10 +711,6 @@ def dap_event args end when :completions @ui.respond req, result - - # custom request - when :rdbgRecordInspector - @ui.respond req, result else raise "unsupported: #{args.inspect}" end @@ -1026,26 +981,6 @@ def process_dap args end end - def request_rdbgRecordInspector req - logs = [] - log_index = nil - unless @recorder.nil? - log_index = @recorder.log_index - @recorder.log.each{|frames| - crt_frame = frames[0] - logs << { - name: crt_frame.name, - location: { - path: crt_frame.location.path, - line: crt_frame.location.lineno, - }, - depth: crt_frame.frame_depth - } - } - end - event! :dap_result, :rdbgRecordInspector, req, logs: logs, stoppedIndex: log_index - end - def search_const b, expr cs = expr.delete_prefix('::').split('::') [Object, *b.eval('::Module.nesting')].reverse_each{|mod| From 6d0c2672a5afa78b9b729b405a1053e41b4b8030 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 22 Mar 2023 18:05:08 +0900 Subject: [PATCH 095/263] relax authority check to pass on the Windows. fix https://github.com/ruby/vscode-rdbg/issues/169 --- lib/debug/config.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 7ffdd741c..6cd23761d 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -425,8 +425,9 @@ def self.check_dir_authority path unless (dir_uid = fs.uid) == (uid = Process.uid) raise "#{path} uid is #{dir_uid}, but Process.uid is #{uid}" end - unless (dir_mode = fs.mode) == 040700 # 4: dir, 7:rwx - raise "#{path}'s mode is #{dir_mode.to_s(8)} (should be 040700)" + + if fs.world_writable? && !fs.sticky? + raise "#{path} is world writable but not sticky" end path From b860e54b7f7b4c0e5f6368c33cb27dbd8b3d6e48 Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Tue, 10 Jan 2023 13:42:21 -0300 Subject: [PATCH 096/263] Add test for global variable support in DAP and CDP --- test/protocol/variables_test.rb | 59 ++++++++++++++++++++++++++++++ test/support/protocol_test_case.rb | 32 ++++++++++------ 2 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 test/protocol/variables_test.rb diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb new file mode 100644 index 000000000..6df06bfb5 --- /dev/null +++ b/test/protocol/variables_test.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require_relative "../support/protocol_test_case" + +module DEBUGGER__ + class DAPVariablesTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| $a = 1 + 2| $b = 2 + 3| $c = 3 + RUBY + + def test_eval_evaluates_global_variables + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 3 + req_continue + + globals = gather_variables(type: "globals") + + # User defined globals + assert_includes(globals, { name: "$a", value: "1", type: "Integer" }) + assert_includes(globals, { name: "$b", value: "2", type: "Integer" }) + + # Ruby defined globals + assert_includes(globals, { name: "$VERBOSE", value: "false", type: "FalseClass" }) + assert_includes(globals, { name: "$stdout", value: "#>", type: "IO" }) + + req_terminate_debuggee + end + end + end + + class CDPVariablesTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| $a = 1 + 2| $b = 2 + 3| $c = 3 + RUBY + + def test_eval_evaluates_global_variables + run_protocol_scenario PROGRAM, dap: false do + req_add_breakpoint 3 + req_continue + + globals = gather_variables(type: "global") + + # User defined globals + assert_includes(globals, { name: "$a", value: "1", type: "Number" }) + assert_includes(globals, { name: "$b", value: "2", type: "Number" }) + + # Ruby defined globals + assert_includes(globals, { name: "$VERBOSE", value: "false", type: "Boolean" }) + assert_includes(globals, { name: "$stdout", value: "#>", type: "Object" }) + + req_terminate_debuggee + end + end + end +end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index acdcae65c..f09dd2f38 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -206,7 +206,7 @@ def req_terminate_debuggee close_reader end - def assert_locals_result expected, frame_idx: 0 + def gather_variables(frame_idx: 0, type: "locals") case get_target_ui when 'vscode' # get frameId @@ -219,32 +219,40 @@ def assert_locals_result expected, frame_idx: 0 # get variablesReference res = send_dap_request 'scopes', frameId: f_id - locals_scope = res.dig(:body, :scopes).find { |d| d[:presentationHint] == "locals" } + locals_scope = res.dig(:body, :scopes).find { |d| d[:presentationHint] == type } locals_reference = locals_scope[:variablesReference] # get variables res = send_dap_request 'variables', variablesReference: locals_reference - - expected.each do |exp| - if exp[:type] == "String" - exp[:value] = exp[:value].inspect - end - end - - actual_locals = res.dig(:body, :variables).map { |loc| { name: loc[:name], value: loc[:value], type: loc[:type] } } + res.dig(:body, :variables).map { |loc| { name: loc[:name], value: loc[:value], type: loc[:type] } } when 'chrome' current_frame = @crt_frames.first - locals_scope = current_frame[:scopeChain].find { |f| f[:type] == "local" } + locals_scope = current_frame[:scopeChain].find { |f| f[:type] == type } object_id = locals_scope.dig(:object, :objectId) res = send_cdp_request "Runtime.getProperties", objectId: object_id - actual_locals = res.dig(:result, :result).map do |loc| + res.dig(:result, :result).map do |loc| type = loc.dig(:value, :className) || loc.dig(:value, :type).capitalize # TODO: sync this with get_ruby_type { name: loc[:name], value: loc.dig(:value, :description), type: type } end end + end + + def assert_locals_result expected, frame_idx: 0 + case get_target_ui + when 'vscode' + actual_locals = gather_dap_variables(frame_idx: frame_idx, type: "locals") + + expected.each do |exp| + if exp[:type] == "String" + exp[:value] = exp[:value].inspect + end + end + when 'chrome' + actual_locals = gather_variables(type: "local") + end failure_msg = FailureMessage.new{create_protocol_message "result:\n#{JSON.pretty_generate res}"} From 3bbff429eb7c1b5dda1d8e7ec6630947017bf245 Mon Sep 17 00:00:00 2001 From: Emily Samp Date: Wed, 11 Jan 2023 12:19:27 -0600 Subject: [PATCH 097/263] Add test for instance variable ordering in DAP PR #806 sorts instance variables by name before returning them. This commit adds a test that verifies this functionality under the DAP protocol. --- test/protocol/variables_test.rb | 38 +++++++++++++++++++++++++----- test/support/protocol_test_case.rb | 2 +- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb index 6df06bfb5..345bdc4bf 100644 --- a/test/protocol/variables_test.rb +++ b/test/protocol/variables_test.rb @@ -3,7 +3,7 @@ require_relative "../support/protocol_test_case" module DEBUGGER__ - class DAPVariablesTest < ProtocolTestCase + class DAPGlobalVariablesTest < ProtocolTestCase PROGRAM = <<~RUBY 1| $a = 1 2| $b = 2 @@ -18,19 +18,19 @@ def test_eval_evaluates_global_variables globals = gather_variables(type: "globals") # User defined globals - assert_includes(globals, { name: "$a", value: "1", type: "Integer" }) - assert_includes(globals, { name: "$b", value: "2", type: "Integer" }) + assert_includes(globals, { name: "$a", value: "1", type: "Integer", variablesReference: 0 }) + assert_includes(globals, { name: "$b", value: "2", type: "Integer", variablesReference: 0 }) # Ruby defined globals - assert_includes(globals, { name: "$VERBOSE", value: "false", type: "FalseClass" }) - assert_includes(globals, { name: "$stdout", value: "#>", type: "IO" }) + assert_includes(globals, { name: "$VERBOSE", value: "false", type: "FalseClass", variablesReference: 0 }) + assert_includes(globals, { name: "$stdout", value: "#>", type: "IO", variablesReference: 0 }) req_terminate_debuggee end end end - class CDPVariablesTest < ProtocolTestCase + class CDPGlobalVariablesTest < ProtocolTestCase PROGRAM = <<~RUBY 1| $a = 1 2| $b = 2 @@ -56,4 +56,30 @@ def test_eval_evaluates_global_variables end end end + + class DAPInstanceVariableTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| @a = 1 + 2| @c = 3 + 3| @b = 2 + 4| __LINE__ + RUBY + + def test_ordering_instance_variables + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 4 + req_continue + + locals = gather_variables + + variables_reference = locals.find { |local| local[:name] == "%self" }[:variablesReference] + res = send_dap_request 'variables', variablesReference: variables_reference + + instance_vars = res.dig(:body, :variables) + assert_equal instance_vars.map { |var| var[:name] }, ["#class", "@a", "@b", "@c"] + + req_terminate_debuggee + end + end + end end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index f09dd2f38..74dbfb640 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -224,7 +224,7 @@ def gather_variables(frame_idx: 0, type: "locals") # get variables res = send_dap_request 'variables', variablesReference: locals_reference - res.dig(:body, :variables).map { |loc| { name: loc[:name], value: loc[:value], type: loc[:type] } } + res.dig(:body, :variables).map { |loc| { name: loc[:name], value: loc[:value], type: loc[:type], variablesReference: loc[:variablesReference] } } when 'chrome' current_frame = @crt_frames.first locals_scope = current_frame[:scopeChain].find { |f| f[:type] == type } From fb914733e9eb5d46d07ce57d3b49b1a3968e876e Mon Sep 17 00:00:00 2001 From: Andy Waite Date: Fri, 10 Mar 2023 13:22:06 -0500 Subject: [PATCH 098/263] Fix incorrect method name --- test/support/protocol_test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 74dbfb640..352c4eefb 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -243,7 +243,7 @@ def gather_variables(frame_idx: 0, type: "locals") def assert_locals_result expected, frame_idx: 0 case get_target_ui when 'vscode' - actual_locals = gather_dap_variables(frame_idx: frame_idx, type: "locals") + actual_locals = gather_variables(frame_idx: frame_idx, type: "locals") expected.each do |exp| if exp[:type] == "String" From 79a8403444d09a4ab0e9f14e080757ac86af26bd Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 15:24:33 +0900 Subject: [PATCH 099/263] dap/cdp_result -> protocol_result From ThreadClient it retunrs :dap_result or :cdp_result to the SESSION. This patch renames it to `:protocol_result` and it will be handled by `process_protocol_result`. --- lib/debug/server_cdp.rb | 12 ++++++------ lib/debug/server_dap.rb | 14 +++++++------- lib/debug/session.rb | 7 ++----- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 6eb6fd678..002aa7809 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -823,7 +823,7 @@ def process_protocol_request req end end - def cdp_event args + def process_protocol_result args type, req, result = args case type @@ -1013,7 +1013,7 @@ def process_cdp args result[:data] = evaluate_result exception result[:reason] = 'exception' end - event! :cdp_result, :backtrace, req, result + event! :protocol_result, :backtrace, req, result when :evaluate res = {} fid, expr, group = args @@ -1074,7 +1074,7 @@ def process_cdp args end res[:result] = evaluate_result(result) - event! :cdp_result, :evaluate, req, message: message, response: res, output: output + event! :protocol_result, :evaluate, req, message: message, response: res, output: output when :scope fid = args.shift frame = @target_frames[fid] @@ -1097,7 +1097,7 @@ def process_cdp args vars.unshift variable(name, val) end end - event! :cdp_result, :scope, req, vars + event! :protocol_result, :scope, req, vars when :properties oid = args.shift result = [] @@ -1139,14 +1139,14 @@ def process_cdp args } prop += [internalProperty('#class', M_CLASS.bind_call(obj))] end - event! :cdp_result, :properties, req, result: result, internalProperties: prop + event! :protocol_result, :properties, req, result: result, internalProperties: prop when :exception oid = args.shift exc = nil if obj = @obj_map[oid] exc = exceptionDetails obj, obj.to_s end - event! :cdp_result, :exception, req, exceptionDetails: exc + event! :protocol_result, :exception, req, exceptionDetails: exc end end diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 63b75827a..e5c2c1a64 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -664,7 +664,7 @@ def process_protocol_request req end end - def dap_event args + def process_protocol_result args # puts({dap_event: args}.inspect) type, req, result = args @@ -798,7 +798,7 @@ def process_dap args } end - event! :dap_result, :backtrace, req, { + event! :protocol_result, :backtrace, req, { stackFrames: frames, totalFrames: @target_frames.size, } @@ -815,7 +815,7 @@ def process_dap args 0 end - event! :dap_result, :scopes, req, scopes: [{ + event! :protocol_result, :scopes, req, scopes: [{ name: 'Local variables', presentationHint: 'locals', # variablesReference: N, # filled by SESSION @@ -837,7 +837,7 @@ def process_dap args variable(var, val) end - event! :dap_result, :scope, req, variables: vars, tid: self.id + event! :protocol_result, :scope, req, variables: vars, tid: self.id when :variable vid = args.shift obj = @var_map[vid] @@ -885,7 +885,7 @@ def process_dap args end end end - event! :dap_result, :variable, req, variables: (vars || []), tid: self.id + event! :protocol_result, :variable, req, variables: (vars || []), tid: self.id when :evaluate fid, expr, context = args @@ -940,7 +940,7 @@ def process_dap args result = 'Error: Can not evaluate on this frame' end - event! :dap_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result) + event! :protocol_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result) when :completions fid, text = args @@ -950,7 +950,7 @@ def process_dap args words = IRB::InputCompletor::retrieve_completion_data(word, bind: b).compact end - event! :dap_result, :completions, req, targets: (words || []).map{|phrase| + event! :protocol_result, :completions, req, targets: (words || []).map{|phrase| detail = nil if /\b([_a-zA-Z]\w*[!\?]?)\z/ =~ phrase diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3f9541636..ffd333a37 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -350,11 +350,8 @@ def process_event evt wait_command_loop - when :dap_result - dap_event ev_args # server.rb - wait_command_loop - when :cdp_result - cdp_event ev_args + when :protocol_result + process_protocol_result ev_args wait_command_loop end end From 012b4346fd3f2da9d0d30d59afe4523e7cfac928 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 14:39:16 +0900 Subject: [PATCH 100/263] separate 'test_console' and 'test_test' --- Rakefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 1a6747ff4..e070bfe13 100644 --- a/Rakefile +++ b/Rakefile @@ -35,9 +35,14 @@ task :check_readme do end end +desc "Run debug.gem test-framework tests" +Rake::TestTask.new(:test_test) do |t| + t.test_files = FileList["test/support/*_test.rb"] +end + desc "Run all debugger console related tests" Rake::TestTask.new(:test_console) do |t| - t.test_files = FileList["test/console/*_test.rb", "test/support/*_test.rb"] + t.test_files = FileList["test/console/*_test.rb"] end desc "Run all debugger protocols (CAP & DAP) related tests" From cea32796c7ca9722f4c5e927088891bdd8297678 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 15:31:55 +0900 Subject: [PATCH 101/263] `test_all` should also run `test_test` --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index e070bfe13..bf5d31a2c 100644 --- a/Rakefile +++ b/Rakefile @@ -54,4 +54,4 @@ task test: 'test_console' do warn '`rake test` doesn\'t run protocol tests. Use `rake test_all` to test all.' end -task test_all: [:test_console, :test_protocol] +task test_all: [:test_test, :test_console, :test_protocol] From a16b495e3dcd4ebc0990122a72760a35ce2d0d67 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 15:11:11 +0900 Subject: [PATCH 102/263] Omit slow tests for healty CI --- test/support/assertions_test.rb | 6 +++++- test/support/protocol_test_case_test.rb | 4 ++++ test/support/test_case_test.rb | 8 ++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/test/support/assertions_test.rb b/test/support/assertions_test.rb index 8cf08a820..880da0c38 100644 --- a/test/support/assertions_test.rb +++ b/test/support/assertions_test.rb @@ -12,7 +12,7 @@ def program def test_the_helper_takes_a_string_expectation_and_escape_it assert_raise_message(/Expected to include `"foobar\\\\?/) do - debug_code(program) do + debug_code(program, remote: false) do assert_line_text("foobar?") end end @@ -51,6 +51,8 @@ def test_the_helper_raises_an_error_with_invalid_expectation end def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_after_scenarios + omit "too slow now" + assert_raise_message(/Expected to include `"foobar\\\\?/) do prepare_test_environment(program, steps) do debug_code_on_unix_domain_socket() @@ -59,6 +61,8 @@ def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_af end def test_the_test_fails_when_debuggee_on_tcpip_mode_doesnt_exist_after_scenarios + omit "too slow now" + assert_raise_message(/Expected to include `"foobar\\\\?/) do prepare_test_environment(program, steps) do debug_code_on_tcpip() diff --git a/test/support/protocol_test_case_test.rb b/test/support/protocol_test_case_test.rb index 4c132b8ac..54296f86f 100644 --- a/test/support/protocol_test_case_test.rb +++ b/test/support/protocol_test_case_test.rb @@ -5,6 +5,8 @@ module DEBUGGER__ class TestProtocolTestCase < ProtocolTestCase def test_the_test_fails_when_debuggee_doesnt_exit + omit "too slow now" + program = <<~RUBY 1| a=1 RUBY @@ -16,6 +18,8 @@ def test_the_test_fails_when_debuggee_doesnt_exit end def test_the_assertion_failure_takes_presedence_over_debuggee_not_exiting + omit "too slow now" + program = <<~RUBY 1| a = 2 2| b = 3 diff --git a/test/support/test_case_test.rb b/test/support/test_case_test.rb index b87457ac0..ec2f28403 100644 --- a/test/support/test_case_test.rb +++ b/test/support/test_case_test.rb @@ -12,7 +12,7 @@ def program def test_the_test_fails_when_debugger_exits_early assert_raise_message(/Expected all commands\/assertions to be executed/) do - debug_code(program) do + debug_code(program, remote: false) do type 'continue' type 'foo' end @@ -35,7 +35,7 @@ def test_the_test_work_when_debuggee_outputs_many_lines def test_the_test_fails_when_the_repl_prompt_does_not_finish_even_though_scenario_is_empty assert_raise_message(/Expected the REPL prompt to finish/) do - debug_code(program) do + debug_code(program, remote: false) do end end end @@ -61,6 +61,8 @@ def steps end def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_after_scenarios + omit "too slow now" + assert_raise_message(/Expected the debuggee program to finish/) do prepare_test_environment(program, steps) do debug_code_on_unix_domain_socket() @@ -69,6 +71,8 @@ def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_af end def test_the_test_fails_when_debuggee_on_tcpip_mode_doesnt_exist_after_scenarios + omit "too slow now" + assert_raise_message(/Expected the debuggee program to finish/) do prepare_test_environment(program, steps) do debug_code_on_tcpip() From a4afb8c1e9d97cbb0da24cb6c4de8497ab861ff6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 15:43:29 +0900 Subject: [PATCH 103/263] add workflow --- .github/workflows/test_test.yml | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/test_test.yml diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml new file mode 100644 index 000000000..9f83f3719 --- /dev/null +++ b/.github/workflows/test_test.yml @@ -0,0 +1,39 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby + +name: TestTestFramework + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + ruby-version: ['3.0', '3.1', '3.2', 'head', 'debug'] + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, + # change this to (see https://github.com/ruby/setup-ruby#versioning): + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Run tests + run: | + bundle exec rake clobber + bundle exec rake compile + bundle exec rake test_test From 1ce006192d58226045a5ad87cb41d4cf8a417883 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 24 Mar 2023 13:44:22 +0900 Subject: [PATCH 104/263] DAP: rename the method name of custom request Follow up for ruby/debug#939 Change the name from "request_..." to "custom_dap_request_" in UI_DAP and ThreadClient for consistency --- lib/debug/server_dap.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index e5c2c1a64..5ee7897c0 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -457,7 +457,7 @@ def process @q_msg << req else - if respond_to? mid = "request_#{req['command']}" + if respond_to? mid = "custom_dap_request_#{req['command']}" __send__ mid, req else raise "Unknown request: #{req.inspect}" @@ -973,7 +973,7 @@ def process_dap args } else - if respond_to? mid = "request_#{type}" + if respond_to? mid = "custom_dap_request_#{type}" __send__ mid, req else raise "Unknown request: #{args.inspect}" From acb629abd0abc1db335b2bbc2bce9306da4d796c Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Wed, 22 Mar 2023 22:52:44 +0900 Subject: [PATCH 105/263] DAP: support custom request in session class UI_DAP -> Session: custom_dap_request_... Session -> ThreadClient: custom_dap_request_event_... Add "request_event" prefix to clarify it is a response (not Events in DAP) --- lib/debug/server_dap.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 5ee7897c0..2ceed37dd 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -656,7 +656,7 @@ def process_protocol_request req fail_response req end else - if respond_to? mid = "request_#{req['command']}" + if respond_to? mid = "custom_dap_request_#{req['command']}" __send__ mid, req else raise "Unknown request: #{req.inspect}" @@ -712,7 +712,11 @@ def process_protocol_result args when :completions @ui.respond req, result else - raise "unsupported: #{args.inspect}" + if respond_to? mid = "custom_dap_request_event_#{type}" + __send__ mid, req + else + raise "unsupported: #{args.inspect}" + end end end From 7fed621705e0cb477c44d02c6f0883f708a5d121 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 8 Mar 2023 14:40:57 +0800 Subject: [PATCH 106/263] Add test for DAP's command execution through evaluate request --- test/protocol/eval_test.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index 94ac19dc8..c3893be45 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -23,6 +23,19 @@ def test_eval_evaluates_arithmetic_expressions req_terminate_debuggee end end + + def test_eval_executes_commands + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 3 + req_continue + assert_repl_result({value: '', type: nil}, ",b 5 ;; b 6") + req_continue + assert_line_num 5 + req_continue + assert_line_num 6 + req_terminate_debuggee + end + end end class EvaluateOnSomeFramesTest < ProtocolTestCase From 211b319c74dad210646df6180a529942bc37ad4d Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 8 Mar 2023 14:59:17 +0800 Subject: [PATCH 107/263] Enqueue DAP's evaluate command right away --- lib/debug/server_dap.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 2ceed37dd..db0e7b7ca 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -442,10 +442,11 @@ def process expr = req.dig('arguments', 'expression') if /\A\s*,(.+)\z/ =~ expr dbg_expr = $1 + dbg_expr.split(';;') { |cmd| @q_msg << cmd } + send_response req, result: "", variablesReference: 0 - debugger do: dbg_expr else @q_msg << req end From f190b2877f33719fcbdc47a26381ebf68d444d7c Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 24 Mar 2023 18:32:18 +0900 Subject: [PATCH 108/263] DAP: echo back the given command on `, debug_command` form. --- lib/debug/server_dap.rb | 4 ++-- test/protocol/eval_test.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index db0e7b7ca..4c8d7d8ad 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -441,11 +441,11 @@ def process when 'evaluate' expr = req.dig('arguments', 'expression') if /\A\s*,(.+)\z/ =~ expr - dbg_expr = $1 + dbg_expr = $1.strip dbg_expr.split(';;') { |cmd| @q_msg << cmd } send_response req, - result: "", + result: "(rdbg:command) #{dbg_expr}", variablesReference: 0 else @q_msg << req diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index c3893be45..ee56a63e8 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -28,7 +28,7 @@ def test_eval_executes_commands run_protocol_scenario PROGRAM, cdp: false do req_add_breakpoint 3 req_continue - assert_repl_result({value: '', type: nil}, ",b 5 ;; b 6") + assert_repl_result({value: '(rdbg:command) b 5 ;; b 6', type: nil}, ",b 5 ;; b 6") req_continue assert_line_num 5 req_continue From b01abec912bb306a946ac5d8d882a6ffdb26a328 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sun, 26 Mar 2023 02:50:15 +0900 Subject: [PATCH 109/263] remain breakpoints on reloaded files Breakpoints should be remained on reloaded files. To make sure maintaining loaded file names. fix https://github.com/ruby/debug/issues/870 --- lib/debug/breakpoint.rb | 14 +++++----- lib/debug/server_dap.rb | 1 - lib/debug/session.rb | 47 +++++++++++++++------------------- lib/debug/source_repository.rb | 2 +- test/console/break_test.rb | 38 ++++++++++++++++++++++++++- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/lib/debug/breakpoint.rb b/lib/debug/breakpoint.rb index 65161f919..13e9c428b 100644 --- a/lib/debug/breakpoint.rb +++ b/lib/debug/breakpoint.rb @@ -101,10 +101,6 @@ def skip_path?(path) def generate_label(name) colorize(" BP - #{name} ", [:YELLOW, :BOLD, :REVERSE]) end - - def pending_until_load? - false - end end if RUBY_VERSION.to_f <= 2.7 @@ -163,10 +159,6 @@ def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: @pending = !@iseq end - def pending_until_load? - @pending - end - def setup return unless @type @@ -207,6 +199,8 @@ def activate iseq, event, line if @pending && !@oneshot DEBUGGER__.info "#{self} is activated." end + + @pending = false end def activate_exact iseq, events, line @@ -299,6 +293,10 @@ def to_s def inspect "<#{self.class.name} #{self.to_s}>" end + + def path_is? path + DEBUGGER__.compare_path(@path, path) + end end class CatchBreakpoint < Breakpoint diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 4c8d7d8ad..168c0743a 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -314,7 +314,6 @@ def process when 'setBreakpoints' req_path = args.dig('source', 'path') path = UI_DAP.local_to_remote_path(req_path) - if path SESSION.clear_line_breakpoints path diff --git a/lib/debug/session.rb b/lib/debug/session.rb index ffd333a37..b2ee5e50a 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -133,13 +133,11 @@ def initialize @commands = {} @unsafe_context = false - has_keep_script_lines = RubyVM.respond_to? :keep_script_lines + @has_keep_script_lines = RubyVM.respond_to? :keep_script_lines @tp_load_script = TracePoint.new(:script_compiled){|tp| - if !has_keep_script_lines || bps_pending_until_load? - eval_script = tp.eval_script unless has_keep_script_lines - ThreadClient.current.on_load tp.instruction_sequence, eval_script - end + eval_script = tp.eval_script unless @has_keep_script_lines + ThreadClient.current.on_load tp.instruction_sequence, eval_script } @tp_load_script.enable @@ -1334,10 +1332,6 @@ def ask msg, default = 'Y' # breakpoint management - def bps_pending_until_load? - @bps.any?{|key, bp| bp.pending_until_load?} - end - def iterate_bps deleted_bps = [] i = 0 @@ -1513,7 +1507,7 @@ def clear_breakpoints(&condition) def clear_line_breakpoints path path = resolve_path(path) clear_breakpoints do |k, bp| - bp.is_a?(LineBreakpoint) && DEBUGGER__.compare_path(k.first, path) + bp.is_a?(LineBreakpoint) && bp.path_is?(path) end rescue Errno::ENOENT # just ignore @@ -1737,25 +1731,26 @@ def on_load iseq, src file_path, reloaded = @sr.add(iseq, src) @ui.event :load, file_path, reloaded - pending_line_breakpoints = @bps.find_all do |key, bp| - LineBreakpoint === bp && !bp.iseq - end - - pending_line_breakpoints.each do |_key, bp| - if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path)) - bp.try_activate iseq - end - end - - if reloaded - @bps.find_all do |key, bp| - LineBreakpoint === bp && DEBUGGER__.compare_path(bp.path, file_path) + # check breakpoints + if file_path + @bps.find_all do |_key, bp| + LineBreakpoint === bp && bp.path_is?(file_path) end.each do |_key, bp| - @bps.delete bp.key # to allow duplicate - if nbp = LineBreakpoint.copy(bp, iseq) - add_bp nbp + if !bp.iseq + bp.try_activate iseq + elsif reloaded + @bps.delete bp.key # to allow duplicate + if nbp = LineBreakpoint.copy(bp, iseq) + add_bp nbp + end end end + else # !file_path => file_path is not existing + @bps.find_all do |_key, bp| + LineBreakpoint === bp && !bp.iseq && DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path)) + end.each do |_key, bp| + bp.try_activate iseq + end end end diff --git a/lib/debug/source_repository.rb b/lib/debug/source_repository.rb index b2ef28409..ddcfd6e93 100644 --- a/lib/debug/source_repository.rb +++ b/lib/debug/source_repository.rb @@ -34,7 +34,7 @@ def initialize end def add iseq, src - # do nothing + # only manage loaded file names if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path) if @loaded_file_map.has_key? path return path, true # reloaded diff --git a/test/console/break_test.rb b/test/console/break_test.rb index 239a0ef5f..2b9b1e6f8 100644 --- a/test/console/break_test.rb +++ b/test/console/break_test.rb @@ -819,7 +819,7 @@ def program path RUBY end - def test_break_on_realoded_file + def test_break_on_realoded_file_pending with_extra_tempfile do |extra_file| debug_code(program(extra_file.path)) do type "break #{extra_file.path}:2 do: p :xyzzy" @@ -837,6 +837,42 @@ def test_break_on_realoded_file end end end + + def test_break_on_reloaded_file + code = <<~'DEBUG_CODE' + 1| require 'tempfile' + 2| tf = Tempfile.new('debug_gem_test') + 3| tf.puts(< Date: Thu, 9 Mar 2023 21:43:41 +0800 Subject: [PATCH 110/263] Use better approach to signal remote process' exit status 1. `remote_info.failed_process` stores symbol but we only use the value's presence to check if the process is force-killed. 2. The force-killed status is directly controlled by `kill_safely` through `kill_remote_debuggee`, which is directly called right before we check the status with `remote_info.failed_process`. Combining the two, we can just let `kill_safely` and `kill_remote_debuggee` to return the force-killed status and not storing it in `remote_info`, which already contains a bunch of information. This also eliminates the need to pass `test_info` to `kill_safely`, which makes related code easier to understand and maintain. --- test/support/console_test_case.rb | 2 +- test/support/protocol_test_case.rb | 6 ++---- test/support/test_case.rb | 15 ++++++++------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 081b3f335..15230ccfa 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -200,7 +200,7 @@ def run_test_scenario cmd, test_info # kill debug console process read.close write.close - kill_safely pid, :debugger, test_info + kill_safely pid end end end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 352c4eefb..888b06f51 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -346,8 +346,7 @@ def execute_dap_scenario scenario is_assertion_failure = true raise e ensure - kill_remote_debuggee test_info - if test_info.failed_process && !is_assertion_failure + if kill_remote_debuggee(test_info) && !is_assertion_failure flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @@ -380,8 +379,7 @@ def execute_cdp_scenario_ scenario is_assertion_failure = true raise e ensure - kill_remote_debuggee test_info - if test_info.failed_process && !is_assertion_failure + if kill_remote_debuggee(test_info) && !is_assertion_failure flunk create_protocol_message "Expected the debuggee program to finish" end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 976ad30fc..5b88b6a1e 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -122,17 +122,17 @@ def wait_pid pid, sec true end - def kill_safely pid, name, test_info - return if wait_pid pid, TIMEOUT_SEC - - test_info.failed_process = name + def kill_safely pid + return false if wait_pid pid, TIMEOUT_SEC Process.kill :TERM, pid - return if wait_pid pid, 0.2 + return true if wait_pid pid, 0.2 Process.kill :KILL, pid Process.waitpid(pid) + true rescue Errno::EPERM, Errno::ESRCH + true end def check_error(error, test_info) @@ -142,13 +142,14 @@ def check_error(error, test_info) end def kill_remote_debuggee test_info - return unless r = test_info.remote_info + return false unless r = test_info.remote_info - kill_safely r.pid, :remote, test_info + force_killed = kill_safely r.pid r.reader_thread.kill # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_safely` method. r.r.close r.w.close + force_killed end def setup_remote_debuggee(cmd) From 42de5fd9c99bacb58c39b8a5bdd03418a78b38c3 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 9 Mar 2023 22:22:17 +0800 Subject: [PATCH 111/263] Remove unused failed_process attribute --- test/support/test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5b88b6a1e..5fff5a612 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -14,7 +14,7 @@ module DEBUGGER__ class TestCase < Test::Unit::TestCase TestInfo = Struct.new(:queue, :mode, :prompt_pattern, :remote_info, - :backlog, :last_backlog, :internal_info, :failed_process) + :backlog, :last_backlog, :internal_info) RemoteInfo = Struct.new(:r, :w, :pid, :sock_path, :port, :reader_thread, :debuggee_backlog) From e7061938bf6d19340ee1ae3bf8a8110cd5d7ae01 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 27 Mar 2023 16:56:01 +0900 Subject: [PATCH 112/263] Add "result" as an argument to custom_dap_request_event method The generated result in ThreadClient is passed as "result". We usually use it when returning responses to VS Code in Session class --- lib/debug/server_dap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 168c0743a..829842866 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -713,7 +713,7 @@ def process_protocol_result args @ui.respond req, result else if respond_to? mid = "custom_dap_request_event_#{type}" - __send__ mid, req + __send__ mid, req, result else raise "unsupported: #{args.inspect}" end From 9d2a5c014b1d0bc5321683d8cdb7285c79dc8f82 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 28 Mar 2023 18:05:45 +0900 Subject: [PATCH 113/263] restart all threads on eval When a thread keeps a lock, and REPL runs a code which needs the lock, other threads should make a progress to release the lock. fix https://github.com/ruby/debug/issues/877 --- lib/debug/session.rb | 17 +++++++++++------ lib/debug/thread_client.rb | 10 +++++++++- test/console/eval_test.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index b2ee5e50a..298eefddd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -343,7 +343,7 @@ def process_event evt opt = ev_args[3] add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt) else - # ignore + stop_all_threads end wait_command_loop @@ -900,13 +900,13 @@ def register_default_command # * `p ` # * Evaluate like `p ` on the current frame. register_command 'p' do |arg| - request_tc [:eval, :p, arg.to_s] + request_eval :p, arg.to_s end # * `pp ` # * Evaluate like `pp ` on the current frame. register_command 'pp' do |arg| - request_tc [:eval, :pp, arg.to_s] + request_eval :pp, arg.to_s end # * `eval ` @@ -917,7 +917,7 @@ def register_default_command @ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead." :retry else - request_tc [:eval, :call, arg] + request_eval :call, arg end end @@ -928,7 +928,7 @@ def register_default_command @ui.puts "not supported on the remote console." :retry end - request_tc [:eval, :irb] + request_eval :irb, nil end ### Trace @@ -1148,7 +1148,7 @@ def process_command line @repl_prev_line = nil check_unsafe - request_tc [:eval, :pp, line] + request_eval :pp, line end rescue Interrupt @@ -1164,6 +1164,11 @@ def process_command line return :retry end + def request_eval type, src + restart_all_threads + request_tc [:eval, type, src] + end + def step_command type, arg if type == :until leave_subsession [:step, type, arg] diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index cd79a3205..cbecdf54d 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1230,7 +1230,15 @@ def wait_next_action_ rescue SuspendReplay, SystemExit, Interrupt raise rescue Exception => e - pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace] + STDERR.puts e.cause.inspect + STDERR.puts e.inspect + Thread.list.each{|th| + STDERR.puts "@@@ #{th}" + th.backtrace.each{|b| + STDERR.puts " > #{b}" + } + } + p ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace] raise ensure @returning = false diff --git a/test/console/eval_test.rb b/test/console/eval_test.rb index 6b066b157..ff710cd90 100644 --- a/test/console/eval_test.rb +++ b/test/console/eval_test.rb @@ -35,4 +35,30 @@ def test_eval_evaluates_computation_and_assignment end end end + + class EvalThreadTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| m = Mutex.new; q = Queue.new + 3| th1 = Thread.new do + 4| m.lock; q << true + 5| sleep 1 + 6| m.unlock + 7| end + 8| q.pop # wait for locking + 9| p :ok + RUBY + end + + def test_eval_with_threads + debug_code program do + type 'b 9' + type 'c' + type 'm.lock.nil?' + assert_line_text 'false' + type 'c' + end + end + end end From a8026a677b5fef477f39cae92ac7344222a92a59 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Tue, 28 Mar 2023 18:13:48 +0900 Subject: [PATCH 114/263] CDP: support remote debugging in different environment From investigation by @ko1-san, the path to set breakpoints seems to be sent in "url" field when debugging in different environment such as WSL(running debuggee) and Windows(running Chrome DevTools). I supported "url" field in this PR. --- lib/debug/server_cdp.rb | 62 +++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 002aa7809..35a3681ff 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -558,35 +558,31 @@ def process when 'Debugger.setBreakpointByUrl' line = req.dig('params', 'lineNumber') if regexp = req.dig('params', 'urlRegex') - path = regexp.match(/(.*)\|/)[1].gsub("\\", "") - cond = req.dig('params', 'condition') - src = get_source_code path - end_line = src.lines.count - line = end_line if line > end_line b_id = "1:#{line}:#{regexp}" - if cond != '' - SESSION.add_line_breakpoint(path, line + 1, cond: cond) - else - SESSION.add_line_breakpoint(path, line + 1) - end bps[b_id] = bps.size - # Because we need to return scriptId, responses are returned in SESSION thread. - req['params']['scriptId'] = path - req['params']['lineNumber'] = line - req['params']['breakpointId'] = b_id - @q_msg << req + path = regexp.match(/(.*)\|/)[1].gsub("\\", "") + add_line_breakpoint(req, b_id, path) elsif url = req.dig('params', 'url') b_id = "#{line}:#{url}" - send_response req, - breakpointId: b_id, - locations: [] - elsif hash = req.dig('params', 'scriptHash') - b_id = "#{line}:#{hash}" - send_response req, - breakpointId: b_id, - locations: [] + # When breakpoints are set in Script snippet, non-existent path such as "snippet:///Script%20snippet%20%231" sent. + # That's why we need to check it here. + if File.exist? url + bps[b_id] = bps.size + add_line_breakpoint(req, b_id, url) + else + send_response req, + breakpointId: b_id, + locations: [] + end else - raise 'Unsupported' + if hash = req.dig('params', 'scriptHash') + b_id = "#{line}:#{hash}" + send_response req, + breakpointId: b_id, + locations: [] + else + raise 'Unsupported' + end end when 'Debugger.removeBreakpoint' b_id = req.dig('params', 'breakpointId') @@ -625,6 +621,24 @@ def process @q_msg << 'continue' end + def add_line_breakpoint req, b_id, path + cond = req.dig('params', 'condition') + line = req.dig('params', 'lineNumber') + src = get_source_code path + end_line = src.lines.count + line = end_line if line > end_line + if cond != '' + SESSION.add_line_breakpoint(path, line + 1, cond: cond) + else + SESSION.add_line_breakpoint(path, line + 1) + end + # Because we need to return scriptId, responses are returned in SESSION thread. + req['params']['scriptId'] = path + req['params']['lineNumber'] = line + req['params']['breakpointId'] = b_id + @q_msg << req + end + def del_bp bps, k return bps unless idx = bps[k] From 15793772f2725322c1ce498236c599fe5ff051a5 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 29 Mar 2023 01:00:36 +0900 Subject: [PATCH 115/263] `-v` prints version and do something Without this patch, `rdbg -v target.rb` prints version and terminates the process. With this pach, `-v` prints version and starts debugging for `target.rb`. If no filename is given, terminates the process. --- lib/debug/config.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 6cd23761d..1a95ce2b2 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -265,6 +265,8 @@ def self.parse_argv argv require 'optparse' require_relative 'version' + have_shown_version = false + opt = OptionParser.new do |o| o.banner = "#{$0} [options] -- [debuggee options]" o.separator '' @@ -372,6 +374,16 @@ def self.parse_argv argv o.separator '' o.separator 'Other options:' + o.on('-v', 'Show version number') do + puts o.ver + have_shown_version = true + end + + o.on('--version', 'Show version number and exit') do + puts o.ver + exit + end + o.on("-h", "--help", "Print help") do puts o exit @@ -395,6 +407,14 @@ def self.parse_argv argv opt.parse!(argv) + if argv.empty? + case + when have_shown_version && config[:mode] == :start + pp config + exit + end + end + config end From a676a27f7c866f32bf73a599ef85c366967cc1e2 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 29 Mar 2023 01:47:33 +0900 Subject: [PATCH 116/263] v1.7.2 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 05fad09db..9f98239dc 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.7.1" + VERSION = "1.7.2" end From 24fc36cd6bf989296072cf414c963ecc8ee245a8 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 29 Mar 2023 13:51:16 +0900 Subject: [PATCH 117/263] start 1.8.0 development --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 9f98239dc..2ffc08662 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.7.2" + VERSION = "1.8.0dev" end From 61e378cdf8ac25f95f9ed19e797bed896dcaa3b9 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 29 Mar 2023 10:49:28 +0100 Subject: [PATCH 118/263] Restart threads on DAP evaluation This makes sure DAP evaluation request also doesn't hang. See #947 for the original console implementation. --- lib/debug/server_dap.rb | 2 ++ test/protocol/eval_test.rb | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 829842866..bae1e4dda 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -625,6 +625,7 @@ def process_protocol_request req expr = req.dig('arguments', 'expression') if find_waiting_tc(tid) + restart_all_threads request_tc [:dap, :evaluate, req, fid, expr, context] else fail_response req @@ -701,6 +702,7 @@ def process_protocol_result args register_vars result[:variables], tid @ui.respond req, result when :evaluate + stop_all_threads message = result.delete :message if message @ui.respond req, success: false, message: message diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index ee56a63e8..68add4e04 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -57,4 +57,27 @@ def test_eval_evaluates_arithmetic_expressions end end end + + class EvaluateThreadTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| th0 = Thread.new{sleep} + 2| m = Mutex.new; q = Queue.new + 3| th1 = Thread.new do + 4| m.lock; q << true + 5| sleep 1 + 6| m.unlock + 7| end + 8| q.pop # wait for locking + 9| p :ok + RUBY + + def test_eval_with_threads + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 9 + req_continue + assert_repl_result({value: 'false', type: 'FalseClass'}, 'm.lock.nil?', frame_idx: 0) + req_continue + end + end + end end From 7c21de832b74e2cbf6a23846d6381f1a6c37b8dd Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sat, 1 Apr 2023 23:08:59 +0900 Subject: [PATCH 119/263] CDP: send "Debugger.scriptParsed" only when a new file path is found This change improves the performance in Chrome Debugging We do not have to send "Debugger.scriptParsed" when the path is known --- lib/debug/server_cdp.rb | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 35a3681ff..ef556febd 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -849,27 +849,25 @@ def process_protocol_result args unless s_id = @scr_id_map[path] s_id = (@scr_id_map.size + 1).to_s @scr_id_map[path] = s_id + lineno = 0 + src = '' if path && File.exist?(path) src = File.read(path) + @src_map[s_id] = src + lineno = src.lines.count end - @src_map[s_id] = src - end - if src = @src_map[s_id] - lineno = src.lines.count - else - lineno = 0 - end - frame[:location][:scriptId] = s_id - frame[:functionLocation][:scriptId] = s_id - @ui.fire_event 'Debugger.scriptParsed', + @ui.fire_event 'Debugger.scriptParsed', scriptId: s_id, - url: frame[:url], + url: path, startLine: 0, startColumn: 0, endLine: lineno, endColumn: 0, executionContextId: 1, hash: src.hash.inspect + end + frame[:location][:scriptId] = s_id + frame[:functionLocation][:scriptId] = s_id frame[:scopeChain].each {|s| oid = s.dig(:object, :objectId) From d88994f15541f6dc1e344d74dac3e1a35486c2d5 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sat, 1 Apr 2023 23:31:08 +0900 Subject: [PATCH 120/263] Fix test for ruby/debug#953 --- test/protocol/break_raw_cdp_test.rb | 328 ++-------- test/protocol/call_stack_raw_cdp_test.rb | 201 +----- test/protocol/catch_raw_cdp_test.rb | 139 +--- test/protocol/hover_raw_cdp_test.rb | 260 +------- test/protocol/next_raw_cdp_test.rb | 343 +--------- test/protocol/step_raw_cdp_test.rb | 509 +-------------- test/protocol/watch_raw_cdp_test.rb | 796 ++++------------------- 7 files changed, 277 insertions(+), 2299 deletions(-) diff --git a/test/protocol/break_raw_cdp_test.rb b/test/protocol/break_raw_cdp_test.rb index edf611210..418e0b2e4 100644 --- a/test/protocol/break_raw_cdp_test.rb +++ b/test/protocol/break_raw_cdp_test.rb @@ -18,7 +18,7 @@ class BreakTest1647164808 < ProtocolTestCase RUBY - def test_1647164808 + def test_1680359282 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -126,70 +126,18 @@ def test_1647164808 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, - method: "Debugger.getPossibleBreakpoints", - params: { - start: { - scriptId: "1", - lineNumber: 0, - columnNumber: 0 - }, - restrictToFunction: true - } - }, - { - id: 11, - result: { - locations: [ - { - scriptId: /.+/, - lineNumber: 0 - } - ] - } - }, - { - id: 12, method: "Debugger.setBreakpointsActive", params: { active: true } }, { - id: 12, + id: 10, result: { } }, { - id: 13, + id: 11, method: "Debugger.setBreakpointByUrl", params: { lineNumber: 3, @@ -199,7 +147,7 @@ def test_1647164808 } }, { - id: 13, + id: 11, result: { breakpointId: /.+/, locations: [ @@ -211,7 +159,7 @@ def test_1647164808 } }, { - id: 14, + id: 12, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -228,7 +176,7 @@ def test_1647164808 } }, { - id: 14, + id: 12, result: { locations: [ { @@ -239,19 +187,19 @@ def test_1647164808 } }, { - id: 15, + id: 13, method: "Debugger.setBreakpointsActive", params: { active: true } }, { - id: 15, + id: 13, result: { } }, { - id: 16, + id: 14, method: "Debugger.setBreakpointByUrl", params: { lineNumber: 6, @@ -261,7 +209,7 @@ def test_1647164808 } }, { - id: 16, + id: 14, result: { breakpointId: /.+/, locations: [ @@ -273,7 +221,7 @@ def test_1647164808 } }, { - id: 17, + id: 15, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -290,7 +238,7 @@ def test_1647164808 } }, { - id: 18, + id: 16, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -307,7 +255,7 @@ def test_1647164808 } }, { - id: 17, + id: 15, result: { locations: [ { @@ -318,7 +266,7 @@ def test_1647164808 } }, { - id: 18, + id: 16, result: { locations: [ { @@ -329,19 +277,19 @@ def test_1647164808 } }, { - id: 19, + id: 17, method: "Debugger.setBreakpointsActive", params: { active: true } }, { - id: 19, + id: 17, result: { } }, { - id: 20, + id: 18, method: "Debugger.setBreakpointByUrl", params: { lineNumber: 7, @@ -351,7 +299,7 @@ def test_1647164808 } }, { - id: 20, + id: 18, result: { breakpointId: /.+/, locations: [ @@ -363,7 +311,7 @@ def test_1647164808 } }, { - id: 21, + id: 19, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -380,7 +328,7 @@ def test_1647164808 } }, { - id: 22, + id: 20, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -397,7 +345,7 @@ def test_1647164808 } }, { - id: 21, + id: 19, result: { locations: [ { @@ -408,7 +356,7 @@ def test_1647164808 } }, { - id: 23, + id: 21, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -425,7 +373,7 @@ def test_1647164808 } }, { - id: 22, + id: 20, result: { locations: [ { @@ -436,7 +384,7 @@ def test_1647164808 } }, { - id: 23, + id: 21, result: { locations: [ { @@ -447,14 +395,14 @@ def test_1647164808 } }, { - id: 24, + id: 22, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 24, + id: 22, result: { } }, @@ -463,32 +411,6 @@ def test_1647164808 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -576,18 +498,7 @@ def test_1647164808 } }, { - id: 25, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 26, + id: 23, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -598,36 +509,7 @@ def test_1647164808 } }, { - id: 25, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 26, + id: 23, result: { result: [ { @@ -656,14 +538,14 @@ def test_1647164808 } }, { - id: 27, + id: 24, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 27, + id: 24, result: { } }, @@ -672,45 +554,6 @@ def test_1647164808 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -837,36 +680,7 @@ def test_1647164808 } }, { - id: 28, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 28, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 29, + id: 25, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -877,7 +691,7 @@ def test_1647164808 } }, { - id: 29, + id: 25, result: { result: [ { @@ -895,14 +709,14 @@ def test_1647164808 } }, { - id: 30, + id: 26, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 30, + id: 26, result: { } }, @@ -911,32 +725,6 @@ def test_1647164808 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1024,18 +812,7 @@ def test_1647164808 } }, { - id: 31, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 32, + id: 27, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1046,36 +823,7 @@ def test_1647164808 } }, { - id: 31, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 32, + id: 27, result: { result: [ { @@ -1104,14 +852,14 @@ def test_1647164808 } }, { - id: 33, + id: 28, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 33, + id: 28, result: { } } diff --git a/test/protocol/call_stack_raw_cdp_test.rb b/test/protocol/call_stack_raw_cdp_test.rb index 73376a508..602381d64 100644 --- a/test/protocol/call_stack_raw_cdp_test.rb +++ b/test/protocol/call_stack_raw_cdp_test.rb @@ -3,8 +3,7 @@ require_relative '../support/protocol_test_case' module DEBUGGER__ - - class CallStackTest1647167458 < ProtocolTestCase + class CallStackTest1680367946 < ProtocolTestCase PROGRAM = <<~RUBY 1| module Foo 2| class Bar @@ -18,7 +17,7 @@ class CallStackTest1647167458 < ProtocolTestCase RUBY - def test_1647167458 + def test_1680367946 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -126,47 +125,18 @@ def test_1647167458 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, method: "Debugger.setBreakpointsActive", params: { active: true } }, { - id: 11, + id: 10, result: { } }, { - id: 12, + id: 11, method: "Debugger.setBreakpointByUrl", params: { lineNumber: 3, @@ -176,7 +146,7 @@ def test_1647167458 } }, { - id: 12, + id: 11, result: { breakpointId: /.+/, locations: [ @@ -188,7 +158,7 @@ def test_1647167458 } }, { - id: 13, + id: 12, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -205,7 +175,7 @@ def test_1647167458 } }, { - id: 13, + id: 12, result: { locations: [ { @@ -216,14 +186,14 @@ def test_1647167458 } }, { - id: 14, + id: 13, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 14, + id: 13, result: { } }, @@ -232,45 +202,6 @@ def test_1647167458 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -397,18 +328,7 @@ def test_1647167458 } }, { - id: 15, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 16, + id: 14, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -419,25 +339,7 @@ def test_1647167458 } }, { - id: 15, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 16, + id: 14, result: { result: [ { @@ -455,18 +357,7 @@ def test_1647167458 } }, { - id: 17, - method: "Runtime.getProperties", - params: { - objectId: "1:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 18, + id: 15, method: "Runtime.getProperties", params: { objectId: "1:local", @@ -477,36 +368,7 @@ def test_1647167458 } }, { - id: 17, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 18, + id: 15, result: { result: [ { @@ -535,18 +397,7 @@ def test_1647167458 } }, { - id: 19, - method: "Runtime.getProperties", - params: { - objectId: "2:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 20, + id: 16, method: "Runtime.getProperties", params: { objectId: "2:local", @@ -557,25 +408,7 @@ def test_1647167458 } }, { - id: 19, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 20, + id: 16, result: { result: [ { @@ -593,14 +426,14 @@ def test_1647167458 } }, { - id: 21, + id: 17, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 21, + id: 17, result: { } } diff --git a/test/protocol/catch_raw_cdp_test.rb b/test/protocol/catch_raw_cdp_test.rb index db9835b94..c867f2f95 100644 --- a/test/protocol/catch_raw_cdp_test.rb +++ b/test/protocol/catch_raw_cdp_test.rb @@ -4,7 +4,7 @@ module DEBUGGER__ - class CatchTest1647168678 < ProtocolTestCase + class CatchTest1680366940 < ProtocolTestCase PROGRAM = <<~RUBY 1| module Foo 2| class Bar @@ -17,7 +17,7 @@ class CatchTest1647168678 < ProtocolTestCase 9| end RUBY - def test_1647168678 + def test_1680366940 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -125,66 +125,25 @@ def test_1647168678 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, method: "Debugger.setPauseOnExceptions", params: { state: "uncaught" } }, { - id: 11, - result: { - } - }, - { - id: 12, - method: "Debugger.setPauseOnExceptions", - params: { - state: "all" - } - }, - { - id: 12, + id: 10, result: { } }, { - id: 13, + id: 11, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 13, + id: 11, result: { } }, @@ -193,45 +152,6 @@ def test_1647168678 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -365,18 +285,7 @@ def test_1647168678 } }, { - id: 14, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 15, + id: 12, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -387,37 +296,7 @@ def test_1647168678 } }, { - id: 14, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - }, - { - name: "_raised", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - subtype: "error", - className: "RuntimeError" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 15, + id: 12, result: { result: [ { @@ -447,14 +326,14 @@ def test_1647168678 } }, { - id: 16, + id: 13, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 16, + id: 13, result: { } }, diff --git a/test/protocol/hover_raw_cdp_test.rb b/test/protocol/hover_raw_cdp_test.rb index ef4004535..cb2499960 100644 --- a/test/protocol/hover_raw_cdp_test.rb +++ b/test/protocol/hover_raw_cdp_test.rb @@ -4,7 +4,7 @@ module DEBUGGER__ - class HoverTest1647163915 < ProtocolTestCase + class HoverTest1680367110 < ProtocolTestCase PROGRAM = <<~RUBY 1| a = 1 2| b = 2 @@ -14,7 +14,7 @@ class HoverTest1647163915 < ProtocolTestCase RUBY - def test_1647163915 + def test_1680367110 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -177,125 +177,18 @@ def test_1647163915 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "b", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "c", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, - method: "Debugger.getPossibleBreakpoints", - params: { - start: { - scriptId: "1", - lineNumber: 0, - columnNumber: 0 - }, - restrictToFunction: true - } - }, - { - id: 11, - result: { - locations: [ - { - scriptId: /.+/, - lineNumber: 0 - } - ] - } - }, - { - id: 12, method: "Debugger.setBreakpointsActive", params: { active: true } }, { - id: 12, + id: 10, result: { } }, { - id: 13, + id: 11, method: "Debugger.setBreakpointByUrl", params: { lineNumber: 3, @@ -305,7 +198,7 @@ def test_1647163915 } }, { - id: 13, + id: 11, result: { breakpointId: /.+/, locations: [ @@ -317,7 +210,7 @@ def test_1647163915 } }, { - id: 14, + id: 12, method: "Debugger.getPossibleBreakpoints", params: { start: { @@ -334,7 +227,7 @@ def test_1647163915 } }, { - id: 14, + id: 12, result: { locations: [ { @@ -345,14 +238,14 @@ def test_1647163915 } }, { - id: 15, + id: 13, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 15, + id: 13, result: { } }, @@ -361,19 +254,6 @@ def test_1647163915 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 5, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -422,18 +302,7 @@ def test_1647163915 } }, { - id: 16, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 17, + id: 14, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -444,80 +313,7 @@ def test_1647163915 } }, { - id: 16, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 1, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "b", - value: { - type: "number", - description: /.+/, - value: 2, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "c", - value: { - type: "number", - description: /.+/, - value: 3, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 17, + id: 14, result: { result: [ { @@ -590,10 +386,10 @@ def test_1647163915 } }, { - id: 18, + id: 15, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "b0517caf9ad3aa17aec13bda2d6a7e41", + callFrameId: "749f0545d098a59afc45091a1b8edc35", expression: "c", objectGroup: "popover", includeCommandLineAPI: false, @@ -616,7 +412,7 @@ def test_1647163915 } }, { - id: 18, + id: 15, result: { result: { type: "number", @@ -627,22 +423,22 @@ def test_1647163915 } }, { - id: 19, + id: 16, method: "Runtime.releaseObjectGroup", params: { objectGroup: "popover" } }, { - id: 19, + id: 16, result: { } }, { - id: 20, + id: 17, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "b0517caf9ad3aa17aec13bda2d6a7e41", + callFrameId: "749f0545d098a59afc45091a1b8edc35", expression: "b", objectGroup: "popover", includeCommandLineAPI: false, @@ -665,7 +461,7 @@ def test_1647163915 } }, { - id: 20, + id: 17, result: { result: { type: "number", @@ -676,22 +472,22 @@ def test_1647163915 } }, { - id: 21, + id: 18, method: "Runtime.releaseObjectGroup", params: { objectGroup: "popover" } }, { - id: 21, + id: 18, result: { } }, { - id: 22, + id: 19, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "b0517caf9ad3aa17aec13bda2d6a7e41", + callFrameId: "749f0545d098a59afc45091a1b8edc35", expression: "a", objectGroup: "popover", includeCommandLineAPI: false, @@ -714,7 +510,7 @@ def test_1647163915 } }, { - id: 22, + id: 19, result: { result: { type: "number", @@ -725,26 +521,26 @@ def test_1647163915 } }, { - id: 23, + id: 20, method: "Runtime.releaseObjectGroup", params: { objectGroup: "popover" } }, { - id: 23, + id: 20, result: { } }, { - id: 24, + id: 21, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 24, + id: 21, result: { } } diff --git a/test/protocol/next_raw_cdp_test.rb b/test/protocol/next_raw_cdp_test.rb index 25278cda0..b26999c65 100644 --- a/test/protocol/next_raw_cdp_test.rb +++ b/test/protocol/next_raw_cdp_test.rb @@ -4,7 +4,7 @@ module DEBUGGER__ - class NextTest1647162227 < ProtocolTestCase + class NextTest1680366131 < ProtocolTestCase PROGRAM = <<~RUBY 1| module Foo 2| class Bar @@ -18,7 +18,7 @@ class NextTest1647162227 < ProtocolTestCase RUBY - def test_1647162227 + def test_1680366131 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -126,44 +126,15 @@ def test_1647162227 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, method: "Debugger.stepOver", params: { skipList: [ - + ] } }, { - id: 11, + id: 10, result: { } }, @@ -172,32 +143,6 @@ def test_1647162227 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -285,18 +230,7 @@ def test_1647162227 } }, { - id: 12, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 13, + id: 11, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -307,36 +241,7 @@ def test_1647162227 } }, { - id: 12, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 13, + id: 11, result: { result: [ { @@ -365,16 +270,16 @@ def test_1647162227 } }, { - id: 14, + id: 12, method: "Debugger.stepOver", params: { skipList: [ - + ] } }, { - id: 14, + id: 12, result: { } }, @@ -383,45 +288,6 @@ def test_1647162227 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -548,18 +414,7 @@ def test_1647162227 } }, { - id: 15, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 16, + id: 13, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -570,25 +425,7 @@ def test_1647162227 } }, { - id: 15, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 16, + id: 13, result: { result: [ { @@ -606,16 +443,16 @@ def test_1647162227 } }, { - id: 17, + id: 14, method: "Debugger.stepOver", params: { skipList: [ - + ] } }, { - id: 17, + id: 14, result: { } }, @@ -624,32 +461,6 @@ def test_1647162227 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -737,18 +548,7 @@ def test_1647162227 } }, { - id: 18, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 19, + id: 15, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -759,36 +559,7 @@ def test_1647162227 } }, { - id: 18, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 19, + id: 15, result: { result: [ { @@ -817,16 +588,16 @@ def test_1647162227 } }, { - id: 20, + id: 16, method: "Debugger.stepOver", params: { skipList: [ - + ] } }, { - id: 20, + id: 16, result: { } }, @@ -835,32 +606,6 @@ def test_1647162227 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -948,18 +693,7 @@ def test_1647162227 } }, { - id: 21, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 22, + id: 17, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -970,36 +704,7 @@ def test_1647162227 } }, { - id: 21, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 22, + id: 17, result: { result: [ { @@ -1028,16 +733,16 @@ def test_1647162227 } }, { - id: 23, + id: 18, method: "Debugger.stepOver", params: { skipList: [ - + ] } }, { - id: 23, + id: 18, result: { } }, diff --git a/test/protocol/step_raw_cdp_test.rb b/test/protocol/step_raw_cdp_test.rb index 435f6ff91..b9083d1a2 100644 --- a/test/protocol/step_raw_cdp_test.rb +++ b/test/protocol/step_raw_cdp_test.rb @@ -4,7 +4,7 @@ module DEBUGGER__ - class StepTest1647142777 < ProtocolTestCase + class StepTest1680366703 < ProtocolTestCase PROGRAM = <<~RUBY 1| module Foo 2| class Bar @@ -18,23 +18,10 @@ class StepTest1647142777 < ProtocolTestCase RUBY - def test_1647142777 + def test_1680366703 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -126,35 +113,6 @@ def test_1647142777 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -164,7 +122,7 @@ def test_1647142777 } }, { - id: 11, + id: 10, result: { } }, @@ -173,32 +131,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -286,18 +218,7 @@ def test_1647142777 } }, { - id: 12, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 13, + id: 11, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -308,36 +229,7 @@ def test_1647142777 } }, { - id: 12, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 13, + id: 11, result: { result: [ { @@ -366,7 +258,7 @@ def test_1647142777 } }, { - id: 14, + id: 12, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -376,7 +268,7 @@ def test_1647142777 } }, { - id: 14, + id: 12, result: { } }, @@ -385,45 +277,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -550,36 +403,7 @@ def test_1647142777 } }, { - id: 15, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 15, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 16, + id: 13, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -590,7 +414,7 @@ def test_1647142777 } }, { - id: 16, + id: 13, result: { result: [ { @@ -608,7 +432,7 @@ def test_1647142777 } }, { - id: 17, + id: 14, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -618,7 +442,7 @@ def test_1647142777 } }, { - id: 17, + id: 14, result: { } }, @@ -627,32 +451,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -740,18 +538,7 @@ def test_1647142777 } }, { - id: 18, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 19, + id: 15, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -762,36 +549,7 @@ def test_1647142777 } }, { - id: 18, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 19, + id: 15, result: { result: [ { @@ -820,7 +578,7 @@ def test_1647142777 } }, { - id: 20, + id: 16, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -830,7 +588,7 @@ def test_1647142777 } }, { - id: 20, + id: 16, result: { } }, @@ -839,45 +597,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1004,18 +723,7 @@ def test_1647142777 } }, { - id: 21, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 22, + id: 17, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1026,25 +734,7 @@ def test_1647142777 } }, { - id: 21, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 22, + id: 17, result: { result: [ { @@ -1062,7 +752,7 @@ def test_1647142777 } }, { - id: 23, + id: 18, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -1072,7 +762,7 @@ def test_1647142777 } }, { - id: 23, + id: 18, result: { } }, @@ -1081,45 +771,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1246,18 +897,7 @@ def test_1647142777 } }, { - id: 24, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 25, + id: 19, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1268,36 +908,7 @@ def test_1647142777 } }, { - id: 24, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Class" - }, - configurable: true, - enumerable: true - }, - { - name: "_return", - value: { - type: "string", - description: /.+/, - value: /.+/, - objectId: /.+/ - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 25, + id: 19, result: { result: [ { @@ -1326,7 +937,7 @@ def test_1647142777 } }, { - id: 26, + id: 20, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -1336,7 +947,7 @@ def test_1647142777 } }, { - id: 26, + id: 20, result: { } }, @@ -1345,32 +956,6 @@ def test_1647142777 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 9, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1458,18 +1043,7 @@ def test_1647142777 } }, { - id: 27, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 28, + id: 21, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1480,36 +1054,7 @@ def test_1647142777 } }, { - id: 27, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Module" - }, - configurable: true, - enumerable: true - }, - { - name: "bar", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 28, + id: 21, result: { result: [ { @@ -1538,7 +1083,7 @@ def test_1647142777 } }, { - id: 29, + id: 22, method: "Debugger.stepInto", params: { breakOnAsyncCall: true, @@ -1548,7 +1093,7 @@ def test_1647142777 } }, { - id: 29, + id: 22, result: { } }, diff --git a/test/protocol/watch_raw_cdp_test.rb b/test/protocol/watch_raw_cdp_test.rb index 656d7c8ee..f836e4d6f 100644 --- a/test/protocol/watch_raw_cdp_test.rb +++ b/test/protocol/watch_raw_cdp_test.rb @@ -3,7 +3,7 @@ require_relative '../support/protocol_test_case' module DEBUGGER__ - class WatchTest1647161607 < ProtocolTestCase + class WatchTest1680367761 < ProtocolTestCase PROGRAM = <<~RUBY 1| a = 2 2| a += 1 @@ -14,7 +14,7 @@ class WatchTest1647161607 < ProtocolTestCase 7| f = 6 RUBY - def test_1647161607 + def test_1680367761 run_cdp_scenario PROGRAM do [ *INITIALIZE_CDP_MSGS, @@ -166,129 +166,9 @@ def test_1647161607 }, { id: 10, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 10, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 11, - method: "Runtime.getProperties", - params: { - objectId: "0:script", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 12, - method: "Runtime.getProperties", - params: { - objectId: "0:global", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: false - } - }, - { - id: 11, - result: { - result: [ - - ] - } - }, - { - id: 12, - result: { - result: [ - - ] - } - }, - { - id: 13, - method: "Runtime.evaluate", - params: { - expression: "(async function(){ await 1; })()", - contextId: "50d169823cddf0a4b6ce990dd7e51844", - throwOnSideEffect: true - } - }, - { - id: 14, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "0f91c69d774fa115d355aa58101be1e3", + callFrameId: "a126f00649ca00f0b32aba84149b1ea9", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -311,7 +191,7 @@ def test_1647161607 } }, { - id: 14, + id: 10, result: { result: { type: "object", @@ -322,7 +202,7 @@ def test_1647161607 } }, { - id: 15, + id: 11, method: "Debugger.stepOver", params: { skipList: [ @@ -331,7 +211,7 @@ def test_1647161607 } }, { - id: 15, + id: 11, result: { } }, @@ -340,19 +220,6 @@ def test_1647161607 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 7, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -401,33 +268,44 @@ def test_1647161607 } }, { - id: 16, - method: "Runtime.evaluate", + id: 12, + method: "Debugger.evaluateOnCallFrame", params: { + callFrameId: "a126f00649ca00f0b32aba84149b1ea9", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, silent: true, returnByValue: false, - generatePreview: false, - userGesture: false, - awaitPromise: false, - contextId: "50d169823cddf0a4b6ce990dd7e51844" + generatePreview: false } }, { - id: 17, - method: "Runtime.getProperties", + method: "Debugger.scriptParsed", params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true + scriptId: /.+/, + url: "", + startLine: 0, + startColumn: 0, + endLine: 1, + endColumn: 0, + executionContextId: 1, + hash: /.+/ } }, { - id: 18, + id: 12, + result: { + result: { + type: "number", + description: /.+/, + value: 2, + objectId: /.+/ + } + } + }, + { + id: 13, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -438,69 +316,7 @@ def test_1647161607 } }, { - id: 17, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 2, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 18, + id: 13, result: { result: [ { @@ -562,10 +378,10 @@ def test_1647161607 } }, { - id: 19, + id: 14, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "4214a828add392fa49b2b22782a4d3fd", + callFrameId: "6942cc45103f29405a912664c8e4f1fc", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -588,7 +404,7 @@ def test_1647161607 } }, { - id: 19, + id: 14, result: { result: { type: "number", @@ -599,7 +415,7 @@ def test_1647161607 } }, { - id: 20, + id: 15, method: "Debugger.stepOver", params: { skipList: [ @@ -608,7 +424,7 @@ def test_1647161607 } }, { - id: 20, + id: 15, result: { } }, @@ -617,19 +433,6 @@ def test_1647161607 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 7, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -678,10 +481,10 @@ def test_1647161607 } }, { - id: 21, + id: 16, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "249684c74b6e52ac6ef45990ece6e164", + callFrameId: "6942cc45103f29405a912664c8e4f1fc", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -704,7 +507,7 @@ def test_1647161607 } }, { - id: 21, + id: 16, result: { result: { type: "number", @@ -715,18 +518,7 @@ def test_1647161607 } }, { - id: 22, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 23, + id: 17, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -737,69 +529,7 @@ def test_1647161607 } }, { - id: 22, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 3, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 23, + id: 17, result: { result: [ { @@ -861,10 +591,10 @@ def test_1647161607 } }, { - id: 24, + id: 18, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "249684c74b6e52ac6ef45990ece6e164", + callFrameId: "59cd2941422d2a90b887393f6ab12291", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -887,7 +617,7 @@ def test_1647161607 } }, { - id: 24, + id: 18, result: { result: { type: "number", @@ -898,7 +628,7 @@ def test_1647161607 } }, { - id: 25, + id: 19, method: "Debugger.stepOver", params: { skipList: [ @@ -907,7 +637,7 @@ def test_1647161607 } }, { - id: 25, + id: 19, result: { } }, @@ -916,19 +646,6 @@ def test_1647161607 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 7, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -959,146 +676,73 @@ def test_1647161607 object: { type: "object", objectId: /.+/ - } - }, - { - type: "global", - object: { - type: "object", - objectId: /.+/ - } - } - ], - this: { - type: "object" - } - } - ] - } - }, - { - id: 26, - method: "Debugger.evaluateOnCallFrame", - params: { - callFrameId: "c9845cfbf14bfb534a516247d28e699d", - expression: "a", - objectGroup: "watch-group", - includeCommandLineAPI: false, - silent: true, - returnByValue: false, - generatePreview: false - } - }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: "", - startLine: 0, - startColumn: 0, - endLine: 1, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, - { - id: 26, - result: { - result: { - type: "number", - description: /.+/, - value: 4, - objectId: /.+/ - } - } - }, - { - id: 27, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 28, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 27, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 4, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true + } + }, + { + type: "global", + object: { + type: "object", + objectId: /.+/ + } + } + ], + this: { + type: "object" + } } ] } }, { - id: 28, + id: 20, + method: "Debugger.evaluateOnCallFrame", + params: { + callFrameId: "59cd2941422d2a90b887393f6ab12291", + expression: "a", + objectGroup: "watch-group", + includeCommandLineAPI: false, + silent: true, + returnByValue: false, + generatePreview: false + } + }, + { + method: "Debugger.scriptParsed", + params: { + scriptId: /.+/, + url: "", + startLine: 0, + startColumn: 0, + endLine: 1, + endColumn: 0, + executionContextId: 1, + hash: /.+/ + } + }, + { + id: 20, + result: { + result: { + type: "number", + description: /.+/, + value: 4, + objectId: /.+/ + } + } + }, + { + id: 21, + method: "Runtime.getProperties", + params: { + objectId: "0:local", + ownProperties: false, + accessorPropertiesOnly: false, + nonIndexedPropertiesOnly: false, + generatePreview: true + } + }, + { + id: 21, result: { result: [ { @@ -1160,10 +804,10 @@ def test_1647161607 } }, { - id: 29, + id: 22, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "c9845cfbf14bfb534a516247d28e699d", + callFrameId: "75b24efedc7d4376c056f9de46e682e2", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -1186,7 +830,7 @@ def test_1647161607 } }, { - id: 29, + id: 22, result: { result: { type: "number", @@ -1197,7 +841,7 @@ def test_1647161607 } }, { - id: 30, + id: 23, method: "Debugger.stepOver", params: { skipList: [ @@ -1206,7 +850,7 @@ def test_1647161607 } }, { - id: 30, + id: 23, result: { } }, @@ -1215,19 +859,6 @@ def test_1647161607 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 7, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1276,10 +907,10 @@ def test_1647161607 } }, { - id: 31, + id: 24, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "b5aa856edfac6fd69923bad78711fb57", + callFrameId: "75b24efedc7d4376c056f9de46e682e2", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -1302,7 +933,7 @@ def test_1647161607 } }, { - id: 31, + id: 24, result: { result: { type: "number", @@ -1313,18 +944,7 @@ def test_1647161607 } }, { - id: 32, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 33, + id: 25, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1335,69 +955,7 @@ def test_1647161607 } }, { - id: 32, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 4, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "number", - description: /.+/, - value: 4, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 33, + id: 25, result: { result: [ { @@ -1459,10 +1017,10 @@ def test_1647161607 } }, { - id: 34, + id: 26, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "b5aa856edfac6fd69923bad78711fb57", + callFrameId: "f09c1dd6f3726f4615e1eecee097699d", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -1485,7 +1043,7 @@ def test_1647161607 } }, { - id: 34, + id: 26, result: { result: { type: "number", @@ -1496,7 +1054,7 @@ def test_1647161607 } }, { - id: 35, + id: 27, method: "Debugger.stepOver", params: { skipList: [ @@ -1505,7 +1063,7 @@ def test_1647161607 } }, { - id: 35, + id: 27, result: { } }, @@ -1514,19 +1072,6 @@ def test_1647161607 params: { } }, - { - method: "Debugger.scriptParsed", - params: { - scriptId: /.+/, - url: /.+/, - startLine: 0, - startColumn: 0, - endLine: 7, - endColumn: 0, - executionContextId: 1, - hash: /.+/ - } - }, { method: "Debugger.paused", params: { @@ -1575,10 +1120,10 @@ def test_1647161607 } }, { - id: 36, + id: 28, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "c0cea16455b6ec62f97edc6eadec2006", + callFrameId: "f09c1dd6f3726f4615e1eecee097699d", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -1601,7 +1146,7 @@ def test_1647161607 } }, { - id: 36, + id: 28, result: { result: { type: "number", @@ -1612,18 +1157,7 @@ def test_1647161607 } }, { - id: 37, - method: "Runtime.getProperties", - params: { - objectId: "0:local", - ownProperties: false, - accessorPropertiesOnly: false, - nonIndexedPropertiesOnly: false, - generatePreview: true - } - }, - { - id: 38, + id: 29, method: "Runtime.getProperties", params: { objectId: "0:local", @@ -1634,69 +1168,7 @@ def test_1647161607 } }, { - id: 37, - result: { - result: [ - { - name: "%self", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "Object" - }, - configurable: true, - enumerable: true - }, - { - name: "a", - value: { - type: "number", - description: /.+/, - value: 5, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "d", - value: { - type: "number", - description: /.+/, - value: 4, - objectId: /.+/ - }, - configurable: true, - enumerable: true - }, - { - name: "e", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - }, - { - name: "f", - value: { - type: "object", - description: /.+/, - objectId: /.+/, - className: "NilClass" - }, - configurable: true, - enumerable: true - } - ] - } - }, - { - id: 38, + id: 29, result: { result: [ { @@ -1758,10 +1230,10 @@ def test_1647161607 } }, { - id: 39, + id: 30, method: "Debugger.evaluateOnCallFrame", params: { - callFrameId: "c0cea16455b6ec62f97edc6eadec2006", + callFrameId: "17f8a6576d5c28763f42a0c7aadd3e4b", expression: "a", objectGroup: "watch-group", includeCommandLineAPI: false, @@ -1784,7 +1256,7 @@ def test_1647161607 } }, { - id: 39, + id: 30, result: { result: { type: "number", @@ -1795,14 +1267,14 @@ def test_1647161607 } }, { - id: 40, + id: 31, method: "Debugger.resume", params: { terminateOnResume: false } }, { - id: 40, + id: 31, result: { } } From 80644fcf4ec87d6c745b13abf5e083e41de56f86 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 2 Apr 2023 20:08:24 +0900 Subject: [PATCH 121/263] Kill a debuggee process fastly if a test fails If AssertionFailedError occurs, we can send signals soon without waiting first. --- test/support/assertions_test.rb | 4 ---- test/support/console_test_case.rb | 7 +++++-- test/support/protocol_test_case.rb | 16 ++++++++++++---- test/support/protocol_test_case_test.rb | 2 -- test/support/test_case.rb | 10 ++++++---- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/test/support/assertions_test.rb b/test/support/assertions_test.rb index 880da0c38..e964c7b6a 100644 --- a/test/support/assertions_test.rb +++ b/test/support/assertions_test.rb @@ -51,8 +51,6 @@ def test_the_helper_raises_an_error_with_invalid_expectation end def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_after_scenarios - omit "too slow now" - assert_raise_message(/Expected to include `"foobar\\\\?/) do prepare_test_environment(program, steps) do debug_code_on_unix_domain_socket() @@ -61,8 +59,6 @@ def test_the_test_fails_when_debuggee_on_unix_domain_socket_mode_doesnt_exist_af end def test_the_test_fails_when_debuggee_on_tcpip_mode_doesnt_exist_after_scenarios - omit "too slow now" - assert_raise_message(/Expected to include `"foobar\\\\?/) do prepare_test_environment(program, steps) do debug_code_on_tcpip() diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 15230ccfa..821cfc824 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -195,12 +195,15 @@ def run_test_scenario cmd, test_info # result of `gets` return this exception in some platform rescue Timeout::Error assert_block(create_message("TIMEOUT ERROR (#{TIMEOUT_SEC} sec)", test_info)) { false } + rescue Test::Unit::AssertionFailedError + is_assertion_failure = true + raise ensure - kill_remote_debuggee test_info + kill_remote_debuggee test_info, force: is_assertion_failure # kill debug console process read.close write.close - kill_safely pid + kill_safely pid, force: is_assertion_failure end end end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 888b06f51..55cb5808e 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -346,8 +346,12 @@ def execute_dap_scenario scenario is_assertion_failure = true raise e ensure - if kill_remote_debuggee(test_info) && !is_assertion_failure - flunk create_protocol_message "Expected the debuggee program to finish" + if is_assertion_failure + kill_remote_debuggee(test_info, force: true) + else + if kill_remote_debuggee(test_info) + flunk create_protocol_message "Expected the debuggee program to finish" + end end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @reader_thread&.kill @@ -379,8 +383,12 @@ def execute_cdp_scenario_ scenario is_assertion_failure = true raise e ensure - if kill_remote_debuggee(test_info) && !is_assertion_failure - flunk create_protocol_message "Expected the debuggee program to finish" + if is_assertion_failure + kill_remote_debuggee(test_info, force: true) + else + if kill_remote_debuggee(test_info) + flunk create_protocol_message "Expected the debuggee program to finish" + end end # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_remote_debuggee` method. @reader_thread&.kill diff --git a/test/support/protocol_test_case_test.rb b/test/support/protocol_test_case_test.rb index 54296f86f..1b1c723cf 100644 --- a/test/support/protocol_test_case_test.rb +++ b/test/support/protocol_test_case_test.rb @@ -18,8 +18,6 @@ def test_the_test_fails_when_debuggee_doesnt_exit end def test_the_assertion_failure_takes_presedence_over_debuggee_not_exiting - omit "too slow now" - program = <<~RUBY 1| a = 2 2| b = 3 diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5fff5a612..fae5b9f58 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -122,8 +122,10 @@ def wait_pid pid, sec true end - def kill_safely pid - return false if wait_pid pid, TIMEOUT_SEC + def kill_safely pid, force: false + unless force + return false if wait_pid pid, TIMEOUT_SEC + end Process.kill :TERM, pid return true if wait_pid pid, 0.2 @@ -141,10 +143,10 @@ def check_error(error, test_info) end end - def kill_remote_debuggee test_info + def kill_remote_debuggee test_info, force: false return false unless r = test_info.remote_info - force_killed = kill_safely r.pid + force_killed = kill_safely r.pid, force: force r.reader_thread.kill # Because the debuggee may be terminated by executing the following operations, we need to run them after `kill_safely` method. r.r.close From 9047fc80a3c5b86e2787ef5d002973bd47d11101 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 2 Apr 2023 22:45:31 +0900 Subject: [PATCH 122/263] Retry connecting in test for attaching to CDP server Currently, we have a random failure such as Errno::ECONNRESET in test for attaching to cdp server(FYI: https://github.com/ruby/debug/actions/runs/4588502898/jobs/8102758399\?pr\=955). We need to retry connecting when Errno::ECONNRESET occurs. --- test/support/protocol_test_case.rb | 60 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 55cb5808e..b8741e3db 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -65,30 +65,9 @@ def attach_to_dap_server end def attach_to_cdp_server - body = get_request HOST, @remote_info.port, '/json' - Timeout.timeout(TIMEOUT_SEC) do - sleep 0.001 until @remote_info.debuggee_backlog.join.include? 'Disconnected.' - end - - sock = Socket.tcp HOST, @remote_info.port - uuid = body[0][:id] - - Timeout.timeout(TIMEOUT_SEC) do - sleep 0.001 until @remote_info.debuggee_backlog.join.match?(/Disconnected\.\R.*Connected/) + retry_connect do + attach_to_cdp_server_ end - - @web_sock = WebSocketClient.new sock - @web_sock.handshake @remote_info.port, uuid - @id = 1 - @reader_thread = Thread.new do - while res = @web_sock.extract_data - @queue.push res - end - rescue Detach - end - sleep 0.001 while @reader_thread.status != 'sleep' - @reader_thread.run - INITIALIZE_CDP_MSGS.each{|msg| send(**msg)} end def req_dap_disconnect(terminate_debuggee:) @@ -324,6 +303,33 @@ def assert_watch_result expected, expression, frame_idx: 0 # Not API + def attach_to_cdp_server_ + body = get_request HOST, @remote_info.port, '/json' + Timeout.timeout(TIMEOUT_SEC) do + sleep 0.001 until @remote_info.debuggee_backlog.join.include? 'Disconnected.' + end + + sock = Socket.tcp HOST, @remote_info.port + uuid = body[0][:id] + + Timeout.timeout(TIMEOUT_SEC) do + sleep 0.001 until @remote_info.debuggee_backlog.join.match?(/Disconnected\.\R.*Connected/) + end + + @web_sock = WebSocketClient.new sock + @web_sock.handshake @remote_info.port, uuid + @id = 1 + @reader_thread = Thread.new do + while res = @web_sock.extract_data + @queue.push res + end + rescue Detach + end + sleep 0.001 while @reader_thread.status != 'sleep' + @reader_thread.run + INITIALIZE_CDP_MSGS.each{|msg| send(**msg)} + end + def execute_dap_scenario scenario ENV['RUBY_DEBUG_TEST_UI'] = 'vscode' @@ -396,9 +402,15 @@ def execute_cdp_scenario_ scenario end def execute_cdp_scenario scenario + retry_connect do + execute_cdp_scenario_ scenario + end + end + + def retry_connect retry_cnt = 0 begin - execute_cdp_scenario_ scenario + yield rescue Errno::ECONNREFUSED if (retry_cnt += 1) > 10 STDERR.puts "retry #{retry_cnt} but can not connect!" From 7b273508f02c9d098796ac99e9cdb7023315470d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 11 Apr 2023 11:14:39 +0900 Subject: [PATCH 123/263] add `Session#exnted_feature` API as experimental --- lib/debug/session.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 298eefddd..2595869f2 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2147,6 +2147,13 @@ def flush end end + # experimental API + def extend_feature session: nil, thread_client: nil, ui: nil + Session.include session if session + ThreadClient.include thread_client if thread_client + @ui.extend ui if ui + end + # manual configuration methods def self.add_line_breakpoint file, line, **kw From ce7e3426483b2b1c79218eba0b06afbcf163435c Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 16 Apr 2023 19:19:38 +0900 Subject: [PATCH 124/263] Move `Session#exnted_feature` into Session class Currently, `exnted_feature` method is defined outside of Session class. This PR fixes it. --- lib/debug/session.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 2595869f2..6007846d7 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1993,6 +1993,13 @@ def before_fork need_lock = true def after_fork_parent @ui.after_fork_parent end + + # experimental API + def extend_feature session: nil, thread_client: nil, ui: nil + Session.include session if session + ThreadClient.include thread_client if thread_client + @ui.extend ui if ui + end end class ProcessGroup @@ -2147,13 +2154,6 @@ def flush end end - # experimental API - def extend_feature session: nil, thread_client: nil, ui: nil - Session.include session if session - ThreadClient.include thread_client if thread_client - @ui.extend ui if ui - end - # manual configuration methods def self.add_line_breakpoint file, line, **kw From 8290437312e10e0b65bdef3314fa0cda8e0cb4ab Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 29 Mar 2023 11:14:00 +0100 Subject: [PATCH 125/263] Improve assert_repl_result for CDP The current implementation doesn't work when the result is a boolean type because the helper calls `#inspect` on the values of `JAVASCRIPT_TYPE_TO_CLASS_MAPS`, which is an array for boolean types. Example failure: ``` <["[TrueClass, FalseClass]"]> was expected to include <"FalseClass">. ``` Since `JAVASCRIPT_TYPE_TO_CLASS_MAPS` is never used in other places, we can just store the String representation of the class name in the hash and thus avoid calling `#inspect` on the values. --- test/protocol/eval_test.rb | 3 ++- test/support/protocol_test_case.rb | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index 68add4e04..c8b03fec9 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -13,13 +13,14 @@ class EvalTest < ProtocolTestCase 6| f = 6 RUBY - def test_eval_evaluates_arithmetic_expressions + def test_eval_evaluates_expressions run_protocol_scenario PROGRAM do req_add_breakpoint 5 req_continue assert_repl_result({value: '2', type: 'Integer'}, 'a') assert_repl_result({value: '4', type: 'Integer'}, 'd') assert_repl_result({value: '3', type: 'Integer'}, '1+2') + assert_repl_result({value: 'false', type: 'FalseClass'}, 'a == 1') req_terminate_debuggee end end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index b8741e3db..ff72aee4e 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -475,10 +475,10 @@ def close_reader HOST = '127.0.0.1' JAVASCRIPT_TYPE_TO_CLASS_MAPS = { - 'string' => String, - 'number' => Integer, - 'boolean' => [TrueClass, FalseClass], - 'symbol' => Symbol + 'string' => "String", + 'number' => "Integer", + 'boolean' => ["TrueClass", "FalseClass"], + 'symbol' => "Symbol" } def assert_eval_result context, expression, expected, frame_idx @@ -517,7 +517,7 @@ def assert_eval_result context, expression, expected, frame_idx failure_msg = FailureMessage.new{create_protocol_message "result:\n#{JSON.pretty_generate res}"} - cl = res.dig(:result, :result, :className) || JAVASCRIPT_TYPE_TO_CLASS_MAPS[res.dig(:result, :result, :type)].inspect + cl = res.dig(:result, :result, :className) || JAVASCRIPT_TYPE_TO_CLASS_MAPS[res.dig(:result, :result, :type)] result_type = Array cl assert_include result_type, expected[:type], failure_msg From 0ec2cafd16b34dfffbfbb580d177d7568289c8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20G=C3=A9n=C3=A9rat?= Date: Wed, 12 Apr 2023 12:28:26 +0100 Subject: [PATCH 126/263] Fixes typo `lengthddsfsd` --- lib/debug/server_dap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index bae1e4dda..2d44f3b53 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -869,7 +869,7 @@ def process_dap args } when String vars = [ - variable('#lengthddsfsd', obj.length), + variable('#length', obj.length), variable('#encoding', obj.encoding), ] printed_str = value_inspect(obj) From caeb4c97018dee5b11f79e65c8b6b7596ab0c188 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 27 Mar 2023 16:58:20 +0900 Subject: [PATCH 127/263] DAP: introduce Rdbg Inspector --- lib/debug/dap_custom/traceInspector.rb | 334 ++++++++++++++++++++++++ lib/debug/frame_info.rb | 9 + lib/debug/server_dap.rb | 12 + lib/debug/thread_client.rb | 6 +- test/protocol/rdbgTraceInspctor_test.rb | 218 ++++++++++++++++ test/support/protocol_test_case.rb | 64 +++++ 6 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 lib/debug/dap_custom/traceInspector.rb create mode 100644 test/protocol/rdbgTraceInspctor_test.rb diff --git a/lib/debug/dap_custom/traceInspector.rb b/lib/debug/dap_custom/traceInspector.rb new file mode 100644 index 000000000..8bbc022c1 --- /dev/null +++ b/lib/debug/dap_custom/traceInspector.rb @@ -0,0 +1,334 @@ +module DEBUGGER__ + module DAP_TraceInspector + class MultiTracer < Tracer + def initialize ui, evts, trace_params, max_log_size: nil, **kw + @evts = evts + @log = [] + @trace_params = trace_params + if max_log_size + @max_log_size = max_log_size + else + @max_log_size = 50000 + end + @dropped_trace_cnt = 0 + super(ui, **kw) + @type = 'multi' + @name = 'TraceInspector' + end + + attr_accessor :dropped_trace_cnt + attr_reader :log + + def setup + @tracer = TracePoint.new(*@evts){|tp| + next if skip?(tp) + + case tp.event + when :call, :c_call, :b_call + if @trace_params + params = parameters_info tp + end + append(call_trace_log(tp, params: params)) + when :return, :c_return, :b_return + return_str = DEBUGGER__.safe_inspect(tp.return_value, short: true, max_length: 4096) + append(call_trace_log(tp, return_str: return_str)) + when :line + append(line_trace_log(tp)) + end + } + end + + def parameters_info tp + b = tp.binding + tp.parameters.map{|_type, name| + begin + { name: name, value: DEBUGGER__.safe_inspect(b.local_variable_get(name), short: true, max_length: 4096) } + rescue NameError, TypeError + nil + end + }.compact + end + + def call_identifier_str tp + if tp.defined_class + minfo(tp) + else + "block" + end + end + + def append log + if @log.size >= @max_log_size + @dropped_trace_cnt += 1 + @log.shift + end + @log << log + end + + def call_trace_log tp, return_str: nil, params: nil + log = { + depth: DEBUGGER__.frame_depth, + name: call_identifier_str(tp), + threadId: Thread.current.instance_variable_get(:@__thread_client_id), + location: { + path: tp.path, + line: tp.lineno + } + } + log[:returnValue] = return_str if return_str + log[:parameters] = params if params && params.size > 0 + log + end + + def line_trace_log tp + { + depth: DEBUGGER__.frame_depth, + threadId: Thread.current.instance_variable_get(:@__thread_client_id), + location: { + path: tp.path, + line: tp.lineno + } + } + end + + def skip? tp + super || !@evts.include?(tp.event) + end + + def skip_with_pattern?(tp) + super && !tp.method_id&.match?(@pattern) + end + end + + class Custom_Recorder < ThreadClient::Recorder + def initialize max_log_size: nil + if max_log_size + @max_log_size = max_log_size + else + @max_log_size = 50000 + end + @dropped_trace_cnt = 0 + super() + end + + attr_accessor :dropped_trace_cnt + + def append frames + if @log.size >= @max_log_size + @dropped_trace_cnt += 1 + @log.shift + end + @log << frames + end + end + + module Custom_UI_DAP + def custom_dap_request_rdbgTraceInspector(req) + @q_msg << req + end + end + + module Custom_Session + def process_trace_cmd req + cmd = req.dig('arguments', 'subCommand') + case cmd + when 'enable' + events = req.dig('arguments', 'events') + evts = [] + trace_params = false + filter = req.dig('arguments', 'filterRegExp') + max_log_size = req.dig('arguments', 'maxLogSize') + events.each{|evt| + case evt + when 'traceLine' + evts << :line + when 'traceCall' + evts << :call + evts << :b_call + when 'traceReturn' + evts << :return + evts << :b_return + when 'traceParams' + trace_params = true + when 'traceClanguageCall' + evts << :c_call + when 'traceClanguageReturn' + evts << :c_return + else + raise "unknown trace type #{evt}" + end + } + add_tracer MultiTracer.new @ui, evts, trace_params, max_log_size: max_log_size, pattern: filter + @ui.respond req, {} + when 'disable' + if t = find_multi_trace + t.disable + end + @ui.respond req, {} + when 'collect' + logs = [] + if t = find_multi_trace + logs = t.log + if t.dropped_trace_cnt > 0 + @ui.puts "Return #{logs.size} traces and #{t.dropped_trace_cnt} traces are dropped" + else + @ui.puts "Return #{logs.size} traces" + end + t.dropped_trace_cnt = 0 + end + @ui.respond req, logs: logs + else + raise "Unknown trace sub command #{cmd}" + end + return :retry + end + + def find_multi_trace + @tracers.values.each{|t| + if t.type == 'multi' + return t + end + } + return nil + end + + def process_record_cmd req + cmd = req.dig('arguments', 'subCommand') + case cmd + when 'enable' + @tc << [:dap, :rdbgTraceInspector, req] + when 'disable' + @tc << [:dap, :rdbgTraceInspector, req] + when 'step' + tid = req.dig('arguments', 'threadId') + count = req.dig('arguments', 'count') + if tc = find_waiting_tc(tid) + @ui.respond req, {} + tc << [:step, :in, count] + else + fail_response req + end + when 'stepBack' + tid = req.dig('arguments', 'threadId') + count = req.dig('arguments', 'count') + if tc = find_waiting_tc(tid) + @ui.respond req, {} + tc << [:step, :back, count] + else + fail_response req + end + when 'collect' + tid = req.dig('arguments', 'threadId') + if tc = find_waiting_tc(tid) + tc << [:dap, :rdbgTraceInspector, req] + else + fail_response req + end + else + raise "Unknown record sub command #{cmd}" + end + end + + def custom_dap_request_rdbgTraceInspector(req) + cmd = req.dig('arguments', 'command') + case cmd + when 'trace' + process_trace_cmd req + when 'record' + process_record_cmd req + else + raise "Unknown command #{cmd}" + end + end + + def custom_dap_request_event_rdbgTraceInspector(req, result) + cmd = req.dig('arguments', 'command') + case cmd + when 'record' + process_event_record_cmd(req, result) + else + raise "Unknown command #{cmd}" + end + end + + def process_event_record_cmd(req, result) + cmd = req.dig('arguments', 'subCommand') + case cmd + when 'enable' + @ui.respond req, {} + when 'disable' + @ui.respond req, {} + when 'collect' + cnt = result.delete :dropped_trace_cnt + if cnt > 0 + @ui.puts "Return #{result[:logs].size} traces and #{cnt} traces are dropped" + else + @ui.puts "Return #{result[:logs].size} traces" + end + @ui.respond req, result + else + raise "Unknown command #{cmd}" + end + end + end + + module Custom_ThreadClient + def custom_dap_request_rdbgTraceInspector(req) + cmd = req.dig('arguments', 'command') + case cmd + when 'record' + process_record_cmd(req) + else + raise "Unknown command #{cmd}" + end + end + + def process_record_cmd(req) + cmd = req.dig('arguments', 'subCommand') + case cmd + when 'enable' + size = req.dig('arguments', 'maxLogSize') + @recorder = Custom_Recorder.new max_log_size: size + @recorder.enable + event! :protocol_result, :rdbgTraceInspector, req + when 'disable' + if @recorder&.enabled? + @recorder.disable + end + @recorder = nil + event! :protocol_result, :rdbgTraceInspector, req + when 'collect' + logs = [] + log_index = nil + unless @recorder.nil? + log_index = @recorder.log_index + @recorder.log.each{|frames| + crt_frame = frames[0] + log = { + name: crt_frame.name, + location: { + path: crt_frame.location.path, + line: crt_frame.location.lineno, + }, + depth: crt_frame.frame_depth + } + if params = crt_frame.iseq_parameters_info + log[:parameters] = params + end + if return_str = crt_frame.return_str + log[:returnValue] = return_str + end + logs << log + } + end + event! :protocol_result, :rdbgTraceInspector, req, logs: logs, stoppedIndex: log_index, dropped_trace_cnt: @recorder.dropped_trace_cnt + @recorder.dropped_trace_cnt = 0 + else + raise "Unknown command #{cmd}" + end + end + end + + ::DEBUGGER__::SESSION.extend_feature session: Custom_Session, thread_client: Custom_ThreadClient, ui: Custom_UI_DAP + end +end diff --git a/lib/debug/frame_info.rb b/lib/debug/frame_info.rb index fa4135935..8eb041969 100644 --- a/lib/debug/frame_info.rb +++ b/lib/debug/frame_info.rb @@ -147,6 +147,15 @@ def local_variables end end + def iseq_parameters_info + case frame_type + when :block, :method + parameters_info + else + nil + end + end + def parameters_info vars = iseq.parameters_symbols vars.map{|var| diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 2d44f3b53..c7bf681ed 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -274,6 +274,14 @@ def recv_request retry end + def load_rdbgExtension req + if exts = req.dig('arguments', 'rdbgExtension') + exts.each{|ext| + require_relative "dap_custom/#{File.basename(ext)}" + } + end + end + def process while req = recv_request raise "not a request: #{req.inspect}" unless req['type'] == 'request' @@ -288,6 +296,8 @@ def process UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true @nonstop = true + load_rdbgExtension req + when 'attach' send_response req UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') @@ -298,6 +308,8 @@ def process @nonstop = false end + load_rdbgExtension req + when 'configurationDone' send_response req diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index cbecdf54d..05d2ca077 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1300,10 +1300,14 @@ def initialize frame._callee = b.eval('__callee__') end } - @log << frames + append(frames) } end + def append frames + @log << frames + end + def enable unless @tp_recorder.enabled? @log.clear diff --git a/test/protocol/rdbgTraceInspctor_test.rb b/test/protocol/rdbgTraceInspctor_test.rb new file mode 100644 index 000000000..18a94b61f --- /dev/null +++ b/test/protocol/rdbgTraceInspctor_test.rb @@ -0,0 +1,218 @@ +# frozen_string_literal: true + +require_relative '../support/protocol_test_case' + +module DEBUGGER__ + class RdbgTraceInspectorTraceTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| def foo + 2| 'bar' + 3| end + 4| foo + 5| foo + RUBY + + def test_defaut_setting + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_trace_enable + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_trace_collect_result( + [ + { + returnValue: "\"bar\"", + name: 'Object#foo', + location: { + line: 3, + } + }, + { + name: 'Object#foo', + location: { + line: 1, + } + }, + { + location: { + line: 4, + } + }, + ] + ) + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + + def test_call_event + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_trace_enable(events: ['traceCall']) + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_trace_collect_result( + [ + { + name: 'Object#foo', + location: { + line: 1, + } + }, + ] + ) + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + + def test_return_event + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_trace_enable(events: ['traceReturn']) + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_trace_collect_result( + [ + { + returnValue: "\"bar\"", + name: 'Object#foo', + location: { + line: 3, + } + }, + ] + ) + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + + def test_line_event + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_trace_enable(events: ['traceLine']) + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_trace_collect_result( + [ + { + location: { + line: 4, + } + }, + ] + ) + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + + def test_restart_trace + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_trace_enable + req_rdbgTraceInspector_trace_disable + req_rdbgTraceInspector_trace_enable(events: ['traceLine']) + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_trace_collect_result( + [ + { + location: { + line: 4, + } + }, + ] + ) + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + end + + class RdbgTraceInspectorRecordTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| module Foo + 2| class Bar + 3| def self.a + 4| "hello" + 5| end + 6| end + 7| Bar.a + 8| bar = Bar.new + 9| end + RUBY + + def test_defaut_setting + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_record_enable + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_record_collect_result( + [ + { + name: "", + location: { + line: 2, + } + }, + { + name: "", + location: { + line: 3, + } + } + ] + ) + req_rdbgTraceInspector_record_step_back 4 + assert_line_num 2 + req_rdbgTraceInspector_record_step 1 + assert_line_num 3 + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + + def test_restart_trace + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + run_protocol_scenario(PROGRAM, cdp: false) do + req_rdbgTraceInspector_record_enable + req_rdbgTraceInspector_record_disable + req_rdbgTraceInspector_record_enable + req_add_breakpoint 5 + req_continue + assert_rdbgTraceInspector_record_collect_result( + [ + { + name: "", + location: { + line: 2, + } + }, + { + name: "", + location: { + line: 3, + } + } + ] + ) + req_rdbgTraceInspector_record_step_back 4 + assert_line_num 2 + req_rdbgTraceInspector_record_step 1 + assert_line_num 3 + req_terminate_debuggee + end + ensure + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + end + end +end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index ff72aee4e..902955c0d 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -219,6 +219,22 @@ def gather_variables(frame_idx: 0, type: "locals") end end + def req_rdbgTraceInspector_trace_enable events: ['traceLine', 'traceCall', 'traceReturn', 'traceParams'] + send_custom_dap_request 'rdbgTraceInspector', command: 'trace', subCommand: 'enable', events: events + end + + def req_rdbgTraceInspector_trace_disable + send_custom_dap_request 'rdbgTraceInspector', command: 'trace', subCommand: 'disable' + end + + def req_rdbgTraceInspector_record_enable + send_custom_dap_request 'rdbgTraceInspector', command: 'record', subCommand: 'enable' + end + + def req_rdbgTraceInspector_record_disable + send_custom_dap_request 'rdbgTraceInspector', command: 'record', subCommand: 'disable' + end + def assert_locals_result expected, frame_idx: 0 case get_target_ui when 'vscode' @@ -301,8 +317,51 @@ def assert_watch_result expected, expression, frame_idx: 0 end end + def req_rdbgTraceInspector_record_step_back count + send_custom_dap_request 'rdbgTraceInspector', command: 'record', subCommand: 'stepBack', threadId: 1, count: count + end + + def req_rdbgTraceInspector_record_step count + send_custom_dap_request 'rdbgTraceInspector', command: 'record', subCommand: 'step', threadId: 1, count: count + end + + def assert_rdbgTraceInspector_record_collect_result expected + res = send_custom_dap_request 'rdbgTraceInspector', command: 'record', subCommand: 'collect', threadId: 1 + assert_collect_result(res, expected) do |exp, log| + check_hash_values(exp, log, :name) && + check_hash_values(exp[:location], log[:location], :line) + end + end + + def assert_rdbgTraceInspector_trace_collect_result expected + res = send_custom_dap_request 'rdbgTraceInspector', command: 'trace', subCommand: 'collect' + assert_collect_result(res, expected) do |exp, log| + check_hash_values(exp, log, :returnValue) && + check_hash_values(exp, log, :name) && + check_hash_values(exp[:location], log[:location], :line) + end + end + # Not API + def assert_collect_result res, expected + logs = res.dig(:body, :logs) + expected.each{|exp| + matched = logs.find {|log| + yield exp, log + } + if matched.nil? + msg = create_protocol_message "Expected to include\n`#{JSON.pretty_generate exp}`\nIn\n`#{JSON.pretty_generate logs}`\n" + flunk(msg) + end + } + end + + def check_hash_values hash_a, hash_b, key + hash_a.has_key?(key) == hash_b.has_key?(key) && + hash_a[key] == hash_b[key] + end + def attach_to_cdp_server_ body = get_request HOST, @remote_info.port, '/json' Timeout.timeout(TIMEOUT_SEC) do @@ -558,6 +617,11 @@ def send_dap_request command, **kw res end + def send_custom_dap_request command, **kw + send_request command, **kw + return find_crt_dap_response + end + def send_cdp_request command, **kw send_request command, **kw res = find_crt_cdp_response From f12911d9dcec54bcf3ab1ad80f8c7695cd483e70 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 30 Apr 2023 21:34:15 +0900 Subject: [PATCH 128/263] Access `dropped_trace_cnt` only when `@recorder` is not nil `undefined method `dropped_trace_cnt` for nil:NilClass` occurs when @recorder is nil. This PR fixes it --- lib/debug/dap_custom/traceInspector.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/debug/dap_custom/traceInspector.rb b/lib/debug/dap_custom/traceInspector.rb index 8bbc022c1..902e3a24f 100644 --- a/lib/debug/dap_custom/traceInspector.rb +++ b/lib/debug/dap_custom/traceInspector.rb @@ -300,6 +300,7 @@ def process_record_cmd(req) when 'collect' logs = [] log_index = nil + trace_cnt = 0 unless @recorder.nil? log_index = @recorder.log_index @recorder.log.each{|frames| @@ -320,9 +321,10 @@ def process_record_cmd(req) end logs << log } + trace_cnt = @recorder.dropped_trace_cnt + @recorder.dropped_trace_cnt = 0 end - event! :protocol_result, :rdbgTraceInspector, req, logs: logs, stoppedIndex: log_index, dropped_trace_cnt: @recorder.dropped_trace_cnt - @recorder.dropped_trace_cnt = 0 + event! :protocol_result, :rdbgTraceInspector, req, logs: logs, stoppedIndex: log_index, dropped_trace_cnt: trace_cnt else raise "Unknown command #{cmd}" end From 1c1849f27fe3c20b9cb4cc6c33be94fc769a810e Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 2 May 2023 15:30:21 +0900 Subject: [PATCH 129/263] Omit test_finish_0 because it failed with only reline environment --- test/console/control_flow_commands_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/console/control_flow_commands_test.rb b/test/console/control_flow_commands_test.rb index 93b00f4e0..6e7ff98da 100644 --- a/test/console/control_flow_commands_test.rb +++ b/test/console/control_flow_commands_test.rb @@ -226,6 +226,8 @@ def test_finish end def test_finish_0 + omit "This test failed with only reline environeent. It may be bug of Reline" unless defined?(Readline) + debug_code program do type 'b 8' type 'c' From b0542c77e217dcb00029f8ad26d87a0e27873772 Mon Sep 17 00:00:00 2001 From: Adison Lampert Date: Wed, 29 Mar 2023 12:01:03 -0400 Subject: [PATCH 130/263] Add test for #790 --- test/protocol/variables_test.rb | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb index 345bdc4bf..38a17a3ce 100644 --- a/test/protocol/variables_test.rb +++ b/test/protocol/variables_test.rb @@ -82,4 +82,83 @@ def test_ordering_instance_variables end end end + + class DAPOverwrittenNameMethod < ProtocolTestCase + PROGRAM = <<~RUBY + 1| class Foo + 2| def self.name(value) end + 3| end + 4| f = Foo.new + 5| __LINE__ + RUBY + + def test_overwritten_name_method + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 5 + req_continue + + locals = gather_variables + + variable_info = locals.find { |local| local[:name] == "f" } + + assert_match /#/, variable_info[:value] + assert_match //, variable_info[:value] + assert_match //, variable_info[:value] + assert_equal "Foo", variable_info[:type] + + req_terminate_debuggee + end + end + end end From a767100d885325725bf1b94baaac4e55c065cb3a Mon Sep 17 00:00:00 2001 From: Adison Lampert Date: Wed, 29 Mar 2023 12:16:37 -0400 Subject: [PATCH 131/263] Improve approach to get type name --- lib/debug/server_dap.rb | 17 +++++------------ lib/debug/thread_client.rb | 1 + test/protocol/variables_test.rb | 30 +----------------------------- 3 files changed, 7 insertions(+), 41 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index c7bf681ed..2a329d36c 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -1024,16 +1024,6 @@ def evaluate_result r variable nil, r end - def type_name obj - klass = M_CLASS.bind_call(obj) - - begin - klass.name || klass.to_s - rescue Exception => e - "" - end - end - def variable_ name, obj, indexedVariables: 0, namedVariables: 0 if indexedVariables > 0 || namedVariables > 0 vid = @var_map.size + 1 @@ -1051,17 +1041,20 @@ def variable_ name, obj, indexedVariables: 0, namedVariables: 0 str = value_inspect(obj) end + klass = M_CLASS.bind_call(obj) + type_name = M_NAME.bind_call(klass) + if name { name: name, value: str, - type: type_name(obj), + type: type_name, variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, } else { result: str, - type: type_name(obj), + type: type_name, variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 05d2ca077..cc0a1cdb4 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -14,6 +14,7 @@ module DEBUGGER__ M_RESPOND_TO_P = method(:respond_to?).unbind M_METHOD = method(:method).unbind M_OBJECT_ID = method(:object_id).unbind + M_NAME = method(:name).unbind module SkipPathHelper def skip_path?(path) diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb index 38a17a3ce..35b773c1b 100644 --- a/test/protocol/variables_test.rb +++ b/test/protocol/variables_test.rb @@ -102,35 +102,7 @@ def test_overwritten_name_method variable_info = locals.find { |local| local[:name] == "f" } assert_match /#/, variable_info[:value] - assert_match //, variable_info[:value] - assert_match / Date: Wed, 5 Apr 2023 16:34:57 -0400 Subject: [PATCH 132/263] Add test for anonymous class instance --- lib/debug/server_dap.rb | 4 ++-- test/protocol/variables_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 2a329d36c..681b62a35 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -1047,14 +1047,14 @@ def variable_ name, obj, indexedVariables: 0, namedVariables: 0 if name { name: name, value: str, - type: type_name, + type: type_name || klass.to_s, variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, } else { result: str, - type: type_name, + type: type_name || klass.to_s, variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb index 35b773c1b..8da270715 100644 --- a/test/protocol/variables_test.rb +++ b/test/protocol/variables_test.rb @@ -133,4 +133,26 @@ def test_overwritten_class_method end end end + + class DAPAnonymousClassInstance < ProtocolTestCase + PROGRAM = <<~RUBY + 1| f = Class.new.new + 2| __LINE__ + RUBY + + def test_anonymous_class_instance + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 2 + req_continue + + locals = gather_variables + + variable_info = locals.find { |local| local[:name] == "f" } + assert_match /#/, variable_info[:value] + assert_match /#/, variable_info[:type] + + req_terminate_debuggee + end + end + end end From 5b14e0a50690b1f4c35ebe747d3567f91f32d35c Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 30 Mar 2023 18:35:55 +0100 Subject: [PATCH 133/263] Fix `info c ` when doesn't return a constant Currently, the command `info c ` crashes the debugger when ` is not a constant because it raises an exception. This patch fixes it by changing it to `puts`. This commit also adds 2 test cases for the `info c ` usage. Co-authored-by: Aiden Storey --- lib/debug/thread_client.rb | 2 +- test/console/info_test.rb | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index cc0a1cdb4..1018fc01d 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -613,7 +613,7 @@ def get_consts expr = nil, only_self: false, &block iter_consts _self, &block return else - raise "#{_self.inspect} (by #{expr}) is not a Module." + puts "#{_self.inspect} (by #{expr}) is not a Module." end elsif _self = current_frame&.self cs = {} diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 40b775967..2cf888333 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -248,6 +248,38 @@ def test_info_constant_with_expression type "c" end end + + def test_info_constant_with_expression_errors + debug_code(program) do + type "b 31" + type "c" + assert_line_num 31 + + type "info constants foo" + assert_line_text([ + /eval error: undefined local variable or method `foo' for main/, + /.*/, + /nil \(by foo\) is not a Module./ + ]) + + type "c" + end + end + + def test_info_constant_with_non_module_expression + debug_code(program) do + type "b 31" + type "c" + assert_line_num 31 + + type "info constants 3" + assert_line_text([ + /3 \(by 3\) is not a Module./ + ]) + + type "c" + end + end end class InfoIvarsTest < ConsoleTestCase From a2b3ee22df6e01d2fa093fd1ea00dd0508564ef1 Mon Sep 17 00:00:00 2001 From: Aiden Storey Date: Wed, 5 Apr 2023 17:16:37 -0400 Subject: [PATCH 134/263] Update `info c ` based on PR comment This will now supress any errors during evaluation, still preventing the debugger from crashing. Instead it will now output the `not a Module` message only when the constant is defined. --- lib/debug/thread_client.rb | 15 ++++++++++----- test/console/info_test.rb | 2 -- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 1018fc01d..e28e1c0cf 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -608,12 +608,17 @@ def iter_consts c, names = {} def get_consts expr = nil, only_self: false, &block if expr && !expr.empty? - _self = frame_eval(expr) - if M_KIND_OF_P.bind_call(_self, Module) - iter_consts _self, &block - return + begin + _self = frame_eval(expr, re_raise: true) + rescue Exception => e + # ignore else - puts "#{_self.inspect} (by #{expr}) is not a Module." + if M_KIND_OF_P.bind_call(_self, Module) + iter_consts _self, &block + return + else + puts "#{_self.inspect} (by #{expr}) is not a Module." + end end elsif _self = current_frame&.self cs = {} diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 2cf888333..c14fe5991 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -258,8 +258,6 @@ def test_info_constant_with_expression_errors type "info constants foo" assert_line_text([ /eval error: undefined local variable or method `foo' for main/, - /.*/, - /nil \(by foo\) is not a Module./ ]) type "c" From e3e2a8223fbf0d7e53a84bd88f135c55b5301ca8 Mon Sep 17 00:00:00 2001 From: Ruby Date: Fri, 5 May 2023 03:17:01 +0900 Subject: [PATCH 135/263] follow-up #957 * use `M_NAME` to call `Module#name` * use parens to avoid warnings: `warning: ambiguity between regexp and two divisions...` --- lib/debug/server_dap.rb | 17 ++++++++++++----- test/protocol/variables_test.rb | 8 ++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 681b62a35..db3d66604 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -1024,6 +1024,16 @@ def evaluate_result r variable nil, r end + def type_name obj + klass = M_CLASS.bind_call(obj) + + begin + M_NAME.bind_call(klass) || klass.to_s + rescue Exception => e + "" + end + end + def variable_ name, obj, indexedVariables: 0, namedVariables: 0 if indexedVariables > 0 || namedVariables > 0 vid = @var_map.size + 1 @@ -1041,20 +1051,17 @@ def variable_ name, obj, indexedVariables: 0, namedVariables: 0 str = value_inspect(obj) end - klass = M_CLASS.bind_call(obj) - type_name = M_NAME.bind_call(klass) - if name { name: name, value: str, - type: type_name || klass.to_s, + type: type_name(obj), variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, } else { result: str, - type: type_name || klass.to_s, + type: type_name(obj), variablesReference: vid, indexedVariables: indexedVariables, namedVariables: namedVariables, diff --git a/test/protocol/variables_test.rb b/test/protocol/variables_test.rb index 8da270715..9b82419e8 100644 --- a/test/protocol/variables_test.rb +++ b/test/protocol/variables_test.rb @@ -101,7 +101,7 @@ def test_overwritten_name_method variable_info = locals.find { |local| local[:name] == "f" } - assert_match /#/, variable_info[:value] + assert_match(/\#/, variable_info[:value]) assert_equal "Foo", variable_info[:type] req_terminate_debuggee @@ -126,7 +126,7 @@ def test_overwritten_class_method locals = gather_variables variable_info = locals.find { |local| local[:name] == "f" } - assert_match /#/, variable_info[:value] + assert_match(/\#/, variable_info[:value]) assert_equal "Foo", variable_info[:type] req_terminate_debuggee @@ -148,8 +148,8 @@ def test_anonymous_class_instance locals = gather_variables variable_info = locals.find { |local| local[:name] == "f" } - assert_match /#/, variable_info[:value] - assert_match /#/, variable_info[:type] + assert_match(/\#/, variable_info[:value]) + assert_match(/\#/, variable_info[:type]) req_terminate_debuggee end From 855772d05deafaad1575ccecf5550e3f00ae1633 Mon Sep 17 00:00:00 2001 From: Ruby Date: Fri, 5 May 2023 03:34:49 +0900 Subject: [PATCH 136/263] separate `process` with `process_request` and we can intercept each requests. See https://github.com/ruby/debug/pull/931 --- lib/debug/server_dap.rb | 322 ++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 159 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index db3d66604..fac6dd4bb 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -284,200 +284,204 @@ def load_rdbgExtension req def process while req = recv_request - raise "not a request: #{req.inspect}" unless req['type'] == 'request' - args = req.dig('arguments') + process_request(req) + end + ensure + send_event :terminated unless @sock.closed? + end - case req['command'] + def process_request req + raise "not a request: #{req.inspect}" unless req['type'] == 'request' + args = req.dig('arguments') - ## boot/configuration - when 'launch' - send_response req - # `launch` runs on debuggee on the same file system - UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true - @nonstop = true + case req['command'] - load_rdbgExtension req + ## boot/configuration + when 'launch' + send_response req + # `launch` runs on debuggee on the same file system + UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true + @nonstop = true - when 'attach' - send_response req - UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') + load_rdbgExtension req - if req.dig('arguments', 'nonstop') == true - @nonstop = true - else - @nonstop = false - end + when 'attach' + send_response req + UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') - load_rdbgExtension req + if req.dig('arguments', 'nonstop') == true + @nonstop = true + else + @nonstop = false + end - when 'configurationDone' - send_response req + load_rdbgExtension req - if @nonstop - @q_msg << 'continue' - else - if SESSION.in_subsession? - send_event 'stopped', reason: 'pause', - threadId: 1, # maybe ... - allThreadsStopped: true - end - end + when 'configurationDone' + send_response req - when 'setBreakpoints' - req_path = args.dig('source', 'path') - path = UI_DAP.local_to_remote_path(req_path) - if path - SESSION.clear_line_breakpoints path - - bps = [] - args['breakpoints'].each{|bp| - line = bp['line'] - if cond = bp['condition'] - bps << SESSION.add_line_breakpoint(path, line, cond: cond) - else - bps << SESSION.add_line_breakpoint(path, line) - end - } - send_response req, breakpoints: (bps.map do |bp| {verified: true,} end) - else - send_response req, success: false, message: "#{req_path} is not available" + if @nonstop + @q_msg << 'continue' + else + if SESSION.in_subsession? + send_event 'stopped', reason: 'pause', + threadId: 1, # maybe ... + allThreadsStopped: true end + end - when 'setFunctionBreakpoints' - send_response req + when 'setBreakpoints' + req_path = args.dig('source', 'path') + path = UI_DAP.local_to_remote_path(req_path) + if path + SESSION.clear_line_breakpoints path + + bps = [] + args['breakpoints'].each{|bp| + line = bp['line'] + if cond = bp['condition'] + bps << SESSION.add_line_breakpoint(path, line, cond: cond) + else + bps << SESSION.add_line_breakpoint(path, line) + end + } + send_response req, breakpoints: (bps.map do |bp| {verified: true,} end) + else + send_response req, success: false, message: "#{req_path} is not available" + end - when 'setExceptionBreakpoints' - process_filter = ->(filter_id, cond = nil) { - bp = - case filter_id - when 'any' - SESSION.add_catch_breakpoint 'Exception', cond: cond - when 'RuntimeError' - SESSION.add_catch_breakpoint 'RuntimeError', cond: cond - else - nil - end - { - verified: !bp.nil?, - message: bp.inspect, - } + when 'setFunctionBreakpoints' + send_response req + + when 'setExceptionBreakpoints' + process_filter = ->(filter_id, cond = nil) { + bp = + case filter_id + when 'any' + SESSION.add_catch_breakpoint 'Exception', cond: cond + when 'RuntimeError' + SESSION.add_catch_breakpoint 'RuntimeError', cond: cond + else + nil + end + { + verified: !bp.nil?, + message: bp.inspect, } + } - SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError' - - filters = args.fetch('filters').map {|filter_id| - process_filter.call(filter_id) - } + SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError' - filters += args.fetch('filterOptions', {}).map{|bp_info| - process_filter.call(bp_info['filterId'], bp_info['condition']) + filters = args.fetch('filters').map {|filter_id| + process_filter.call(filter_id) } - send_response req, breakpoints: filters + filters += args.fetch('filterOptions', {}).map{|bp_info| + process_filter.call(bp_info['filterId'], bp_info['condition']) + } - when 'disconnect' - terminate = args.fetch("terminateDebuggee", false) + send_response req, breakpoints: filters - SESSION.clear_all_breakpoints - send_response req + when 'disconnect' + terminate = args.fetch("terminateDebuggee", false) - if SESSION.in_subsession? - if terminate - @q_msg << 'kill!' - else - @q_msg << 'continue' - end - else - if terminate - @q_msg << 'kill!' - pause - end - end + SESSION.clear_all_breakpoints + send_response req - ## control - when 'continue' - @q_msg << 'c' - send_response req, allThreadsContinued: true - when 'next' - begin - @session.check_postmortem - @q_msg << 'n' - send_response req - rescue PostmortemError - send_response req, - success: false, message: 'postmortem mode', - result: "'Next' is not supported while postmortem mode" - end - when 'stepIn' - begin - @session.check_postmortem - @q_msg << 's' - send_response req - rescue PostmortemError - send_response req, - success: false, message: 'postmortem mode', - result: "'stepIn' is not supported while postmortem mode" + if SESSION.in_subsession? + if terminate + @q_msg << 'kill!' + else + @q_msg << 'continue' end - when 'stepOut' - begin - @session.check_postmortem - @q_msg << 'fin' - send_response req - rescue PostmortemError - send_response req, - success: false, message: 'postmortem mode', - result: "'stepOut' is not supported while postmortem mode" + else + if terminate + @q_msg << 'kill!' + pause end - when 'terminate' + end + + ## control + when 'continue' + @q_msg << 'c' + send_response req, allThreadsContinued: true + when 'next' + begin + @session.check_postmortem + @q_msg << 'n' send_response req - exit - when 'pause' + rescue PostmortemError + send_response req, + success: false, message: 'postmortem mode', + result: "'Next' is not supported while postmortem mode" + end + when 'stepIn' + begin + @session.check_postmortem + @q_msg << 's' send_response req - Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid) - when 'reverseContinue' + rescue PostmortemError send_response req, - success: false, message: 'cancelled', - result: "Reverse Continue is not supported. Only \"Step back\" is supported." - when 'stepBack' - @q_msg << req + success: false, message: 'postmortem mode', + result: "'stepIn' is not supported while postmortem mode" + end + when 'stepOut' + begin + @session.check_postmortem + @q_msg << 'fin' + send_response req + rescue PostmortemError + send_response req, + success: false, message: 'postmortem mode', + result: "'stepOut' is not supported while postmortem mode" + end + when 'terminate' + send_response req + exit + when 'pause' + send_response req + Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid) + when 'reverseContinue' + send_response req, + success: false, message: 'cancelled', + result: "Reverse Continue is not supported. Only \"Step back\" is supported." + when 'stepBack' + @q_msg << req - ## query - when 'threads' - send_response req, threads: SESSION.managed_thread_clients.map{|tc| - { id: tc.id, - name: tc.name, - } + ## query + when 'threads' + send_response req, threads: SESSION.managed_thread_clients.map{|tc| + { id: tc.id, + name: tc.name, } + } - when 'evaluate' - expr = req.dig('arguments', 'expression') - if /\A\s*,(.+)\z/ =~ expr - dbg_expr = $1.strip - dbg_expr.split(';;') { |cmd| @q_msg << cmd } + when 'evaluate' + expr = req.dig('arguments', 'expression') + if /\A\s*,(.+)\z/ =~ expr + dbg_expr = $1.strip + dbg_expr.split(';;') { |cmd| @q_msg << cmd } - send_response req, - result: "(rdbg:command) #{dbg_expr}", - variablesReference: 0 - else - @q_msg << req - end - when 'stackTrace', - 'scopes', - 'variables', - 'source', - 'completions' + send_response req, + result: "(rdbg:command) #{dbg_expr}", + variablesReference: 0 + else @q_msg << req + end + when 'stackTrace', + 'scopes', + 'variables', + 'source', + 'completions' + @q_msg << req + else + if respond_to? mid = "custom_dap_request_#{req['command']}" + __send__ mid, req else - if respond_to? mid = "custom_dap_request_#{req['command']}" - __send__ mid, req - else - raise "Unknown request: #{req.inspect}" - end + raise "Unknown request: #{req.inspect}" end end - ensure - send_event :terminated unless @sock.closed? end ## called by the SESSION thread From 697414d3b398147d5603e19a099916e21fd37655 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 5 May 2023 11:18:15 +0900 Subject: [PATCH 137/263] Terminate a test early when it fails Currently the test framework waits 15 seconds and then terminates if a test fails. The reason for waiting 15 seconds is `kill_remote_debuggee` is called without raising `Test::Unit::AssertionFailedError`. We need to raise `Test::Unit::AssertionFailedError` on all modes when a test fails. --- test/support/console_test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 821cfc824..49e0bb87f 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -98,7 +98,7 @@ def debug_code(program, remote: true, &test_steps) th.each do |t| if fail_msg = t.join.value - th.each(&:kill) + th.each{|t| t.raise Test::Unit::AssertionFailedError} flunk fail_msg end end From f4b4ddaf24188488d8363938ea5c5853dd749a83 Mon Sep 17 00:00:00 2001 From: MasanoriOnishi Date: Fri, 5 May 2023 12:53:10 +0900 Subject: [PATCH 138/263] Enable trap function accept Integer --- lib/debug/session.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 6007846d7..4e029fcbd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2524,7 +2524,7 @@ def daemon(*args) module TrapInterceptor def trap sig, *command, &command_proc - case sig&.to_sym + case sig&.to_s&.to_sym when :INT, :SIGINT if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint? return SESSION.save_int_trap(command.empty? ? command_proc : command.first) From 3cf02537a6c5fcd547395bbb267759fc87bb4a73 Mon Sep 17 00:00:00 2001 From: Ruby Date: Sat, 6 May 2023 03:16:38 +0900 Subject: [PATCH 139/263] work correctly with trap(Integer,...) follow up for https://github.com/ruby/debug/pull/976 --- lib/debug/session.rb | 10 ++++++++++ test/console/trap_test.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 4e029fcbd..e9d95775c 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2524,6 +2524,16 @@ def daemon(*args) module TrapInterceptor def trap sig, *command, &command_proc + sym = + case sig + when String + sig.to_sym + when Integer + Signal.signame(sig)&.to_sym + else + sig + end + case sig&.to_s&.to_sym when :INT, :SIGINT if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint? diff --git a/test/console/trap_test.rb b/test/console/trap_test.rb index 4664d3757..17c4ccfa7 100644 --- a/test/console/trap_test.rb +++ b/test/console/trap_test.rb @@ -24,6 +24,32 @@ def test_sigint type 'c' end end + + def test_trap_with + debug_code %q{ + 1| trap(:INT){} # Symbol + 2| _ = 1 + }, remote: false do + type 'n' + type 'n' + end + + debug_code %q{ + 1| trap('INT'){} # String + 2| _ = 1 + }, remote: false do + type 'n' + type 'n' + end + + debug_code %q{ + 1| trap(Signal.list['INT']){} if Signal.list['INT'] # Integer + 2| _ = 1 + }, remote: false do + type 'n' + type 'n' + end + end end end From 3becfa1d66568ee4abb164cb236d1714335c3d6c Mon Sep 17 00:00:00 2001 From: Ruby Date: Fri, 5 May 2023 04:12:20 +0900 Subject: [PATCH 140/263] `no_lineno` config optiopn (default: false) See https://github.com/ruby/debug/issues/881 --- README.md | 3 +++ lib/debug/config.rb | 1 + lib/debug/thread_client.rb | 12 ++++++++---- test/console/config_test.rb | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5e7b72b27..c46a5d058 100644 --- a/README.md +++ b/README.md @@ -476,6 +476,7 @@ config set no_color true * `RUBY_DEBUG_NO_SIGINT_HOOK` (`no_sigint_hook`): Do not suspend on SIGINT (default: false) * `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false) * `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false) + * `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false) * CONTROL * `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths @@ -908,6 +909,8 @@ Attach mode: 'rdbg -A host port' tries to connect to host:port via TCP/IP. Other options: + -v Show version number + --version Show version number and exit -h, --help Print help --util=NAME Utility mode (used by tools) --stop-at-load Stop immediately when the debugging feature is loaded. diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 1a95ce2b2..f6f1a066d 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -21,6 +21,7 @@ module DEBUGGER__ no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"], no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], + no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], # control setting skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index e28e1c0cf..57a802615 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -469,10 +469,14 @@ def get_src(frame, if file_lines = frame.file_lines frame_line = frame.location.lineno - 1 - lines = file_lines.map.with_index do |e, i| - cur = i == frame_line ? '=>' : ' ' - line = colorize_dim('%4d|' % (i+1)) - "#{cur}#{line} #{e}" + if CONFIG[:no_lineno] + lines = file_lines + else + lines = file_lines.map.with_index do |e, i| + cur = i == frame_line ? '=>' : ' ' + line = colorize_dim('%4d|' % (i+1)) + "#{cur}#{line} #{e}" + end end unless start_line diff --git a/test/console/config_test.rb b/test/console/config_test.rb index 9925c017d..589be7488 100644 --- a/test/console/config_test.rb +++ b/test/console/config_test.rb @@ -411,4 +411,23 @@ def test_debugger_takes_log_level_config_from_config_option end end end + + class NoLinenoTest < ConsoleTestCase + def program + <<~RUBY + 1| a = :a + 2| b = :b + 3| c = :c + RUBY + end + + def test_no_lineno + debug_code(program) do + type 'config set no_lineno true' + type 'list' + assert_no_line_text(/^\s*\d/) + type 'c' + end + end + end end From ab2a1edfee2743369bdc325b5cad4cfad8bbf126 Mon Sep 17 00:00:00 2001 From: Ruby Date: Tue, 9 May 2023 02:27:32 +0900 Subject: [PATCH 141/263] support `config.rdbgInitialScripts` for future extensions. And rename: * `load_rdbgExtension` -> `load_extensions` * `config.rdbgExtension` -> `config.rdbgExtensions` --- lib/debug/server_dap.rb | 19 +++++++++++++---- test/protocol/rdbgTraceInspctor_test.rb | 28 ++++++++++++------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index fac6dd4bb..8dbefda8a 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -274,12 +274,23 @@ def recv_request retry end - def load_rdbgExtension req - if exts = req.dig('arguments', 'rdbgExtension') + def load_extensions req + if exts = req.dig('arguments', 'rdbgExtensions') exts.each{|ext| require_relative "dap_custom/#{File.basename(ext)}" } end + + if scripts = req.dig('arguments', 'rdbgInitialScripts') + scripts.each do |script| + begin + eval(script) + rescue Exception => e + puts e.message + puts e.backtrace.inspect + end + end + end end def process @@ -303,7 +314,7 @@ def process_request req UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true @nonstop = true - load_rdbgExtension req + load_extensions req when 'attach' send_response req @@ -315,7 +326,7 @@ def process_request req @nonstop = false end - load_rdbgExtension req + load_extensions req when 'configurationDone' send_response req diff --git a/test/protocol/rdbgTraceInspctor_test.rb b/test/protocol/rdbgTraceInspctor_test.rb index 18a94b61f..f42049b63 100644 --- a/test/protocol/rdbgTraceInspctor_test.rb +++ b/test/protocol/rdbgTraceInspctor_test.rb @@ -13,7 +13,7 @@ class RdbgTraceInspectorTraceTest < ProtocolTestCase RUBY def test_defaut_setting - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_trace_enable req_add_breakpoint 5 @@ -43,11 +43,11 @@ def test_defaut_setting req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end def test_call_event - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_trace_enable(events: ['traceCall']) req_add_breakpoint 5 @@ -65,11 +65,11 @@ def test_call_event req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end def test_return_event - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_trace_enable(events: ['traceReturn']) req_add_breakpoint 5 @@ -88,11 +88,11 @@ def test_return_event req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end def test_line_event - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_trace_enable(events: ['traceLine']) req_add_breakpoint 5 @@ -109,11 +109,11 @@ def test_line_event req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end def test_restart_trace - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_trace_enable req_rdbgTraceInspector_trace_disable @@ -132,7 +132,7 @@ def test_restart_trace req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end end @@ -150,7 +150,7 @@ class RdbgTraceInspectorRecordTest < ProtocolTestCase RUBY def test_defaut_setting - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_record_enable req_add_breakpoint 5 @@ -178,11 +178,11 @@ def test_defaut_setting req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end def test_restart_trace - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtension] = ["traceInspector"] + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments][:rdbgExtensions] = ["traceInspector"] run_protocol_scenario(PROGRAM, cdp: false) do req_rdbgTraceInspector_record_enable req_rdbgTraceInspector_record_disable @@ -212,7 +212,7 @@ def test_restart_trace req_terminate_debuggee end ensure - DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtension + DEBUGGER__::INITIALIZE_DAP_MSGS[1][:arguments].delete :rdbgExtensions end end end From 4ec9d7ab46df09aa87d64e600df8805a3ee0314c Mon Sep 17 00:00:00 2001 From: Ruby Date: Tue, 9 May 2023 11:53:39 +0900 Subject: [PATCH 142/263] v1.8.0 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 2ffc08662..ae8afe5f4 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.8.0dev" + VERSION = "1.8.0" end From 04622258ceff8b28d99afa581b05b62396563b2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:34:17 +0900 Subject: [PATCH 143/263] Bump actions/checkout from 3 to 4 (#1014) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby-macos.yaml | 2 +- .github/workflows/ruby.yml | 2 +- .github/workflows/test_test.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index c756a0538..b2889aab1 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -24,7 +24,7 @@ jobs: ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head', 'debug'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Ruby # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, # change this to (see https://github.com/ruby/setup-ruby#versioning): diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index f3ef96c53..0274941df 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -24,7 +24,7 @@ jobs: ruby-version: ['3.2', 'head'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Ruby # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, # change this to (see https://github.com/ruby/setup-ruby#versioning): diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 5dcc41426..a41da836a 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -24,7 +24,7 @@ jobs: ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Ruby # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, # change this to (see https://github.com/ruby/setup-ruby#versioning): diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 9f83f3719..db4cb9e95 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -24,7 +24,7 @@ jobs: ruby-version: ['3.0', '3.1', '3.2', 'head', 'debug'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Ruby # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, # change this to (see https://github.com/ruby/setup-ruby#versioning): From 5eba4e922e4c7133d9fdfef4526254fda7156779 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Wed, 6 Sep 2023 15:32:27 -0700 Subject: [PATCH 144/263] Stop assuming Integer#times is written in C --- test/console/backtrace_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index 52b1238a1..dd1316ee5 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -22,7 +22,7 @@ def program 14| end 15| end 16| - 17| 3.times do + 17| [1, 2, 3].each do 18| Foo.new.first_call 19| end RUBY @@ -33,7 +33,7 @@ def test_backtrace_prints_c_method_frame type 'b 18' type 'c' type 'bt' - assert_line_text(/\[C\] Integer#times/) + assert_line_text(/\[C\] Array#each/) type 'kill!' end end From 3d0f4e3225c4f88db23b580fea6f391d33a178d8 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 14 Sep 2023 12:22:56 +0100 Subject: [PATCH 145/263] Require Reline 0.3.8+ to avoid frozen issue --- debug.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug.gemspec b/debug.gemspec index f05d0faa7..a07018a77 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -28,5 +28,5 @@ Gem::Specification.new do |spec| spec.extensions = ['ext/debug/extconf.rb'] spec.add_dependency "irb", ">= 1.5.0" # for binding.irb(show_code: false) - spec.add_dependency "reline", ">= 0.3.1" + spec.add_dependency "reline", ">= 0.3.8" end From 3d822a1b8323ec354fbf0cb3ad365d882a04dd02 Mon Sep 17 00:00:00 2001 From: tompng Date: Sat, 5 Aug 2023 22:18:35 +0900 Subject: [PATCH 146/263] Fix prompt list size and colorized code line size to match input line size --- lib/debug/console.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index 2da261662..b44868899 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -56,10 +56,10 @@ def readline_setup prompt Reline.prompt_proc = -> args, *kw do case state = parse_input(args.first, commands) when nil, :command - [prompt, prompt] + [prompt] when :ruby - [prompt.sub('rdbg'){colorize('ruby', [:RED])}] * 2 - end + [prompt.sub('rdbg'){colorize('ruby', [:RED])}] + end * args.size end Reline.completion_proc = -> given do @@ -96,7 +96,7 @@ def readline_setup prompt when nil buff when :ruby - colorize_code(buff.chomp) + colorize_code(buff) end end unless CONFIG[:no_hint] From d93e108f8a2a90e09bda369c6b244ce9b2c42a74 Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Tue, 1 Aug 2023 14:43:39 -0400 Subject: [PATCH 147/263] Disable clone breakpoints trace point events --- lib/debug/session.rb | 12 ++++++++---- test/console/break_test.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index e9d95775c..6a838eec0 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1739,15 +1739,19 @@ def on_load iseq, src # check breakpoints if file_path @bps.find_all do |_key, bp| - LineBreakpoint === bp && bp.path_is?(file_path) + LineBreakpoint === bp && bp.path_is?(file_path) && (iseq.first_lineno..iseq.last_line).cover?(bp.line) end.each do |_key, bp| if !bp.iseq bp.try_activate iseq elsif reloaded @bps.delete bp.key # to allow duplicate - if nbp = LineBreakpoint.copy(bp, iseq) - add_bp nbp - end + + # When we delete a breakpoint from the @bps hash, we also need to deactivate it or else its tracepoint event + # will continue to be enabled and we'll suspend on ghost breakpoints + bp.delete + + nbp = LineBreakpoint.copy(bp, iseq) + add_bp nbp end end else # !file_path => file_path is not existing diff --git a/test/console/break_test.rb b/test/console/break_test.rb index 2b9b1e6f8..dc06f3d1d 100644 --- a/test/console/break_test.rb +++ b/test/console/break_test.rb @@ -873,6 +873,34 @@ def test_break_on_reloaded_file type 'c' end end + + def test_removing_breakpoint_on_reloaded_file + code = <<~'DEBUG_CODE' + 1| require 'tempfile' + 2| tf = Tempfile.new('debug_gem_test', mode: File::TRUNC) + 3| tf.write(<<~RUBY) + 4| def foo + 5| "hello" + 6| end + 7| RUBY + 8| tf.close + 9| load tf.path + 10| alias bar foo + 11| debugger do: "b #{tf.path}:2" + 12| bar + 13| load tf.path + 14| bar + 15| load tf.path + 16| bar + DEBUG_CODE + + debug_code code do + type "c" + assert_line_num 2 + + type "c" + end + end end class BreakAtLineTest < ConsoleTestCase From 8d5c2a9533c1b4efb54a791da198c85e2610fc0c Mon Sep 17 00:00:00 2001 From: takatea Date: Sun, 9 Jul 2023 02:39:06 +0900 Subject: [PATCH 148/263] fix: `load_history` method return the line count of the history Fixed the `load_history` method in the console.rb The following changes: * Load the history only if it doesn't exist * Return value to the line count of the history --- lib/debug/console.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index b44868899..959b940e4 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -224,11 +224,11 @@ def deactivate end def load_history - read_history_file.count{|line| + read_history_file.each{|line| line.strip! history << line unless line.empty? - } + } if history.empty? + history.count end end # class Console end - From 5bc4c51885daf97b89150edeef1301efcbe583a8 Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Sun, 18 Jun 2023 14:30:12 +0900 Subject: [PATCH 149/263] Fix "lib/debug/thread_client.rb:618: warning: assigned but unused variable - e" --- lib/debug/thread_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 57a802615..3ec53fb81 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -614,7 +614,7 @@ def get_consts expr = nil, only_self: false, &block if expr && !expr.empty? begin _self = frame_eval(expr, re_raise: true) - rescue Exception => e + rescue Exception # ignore else if M_KIND_OF_P.bind_call(_self, Module) From 3073129c19dd7a3379eb9667f33e30456efed8af Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Sun, 18 Jun 2023 14:42:28 +0900 Subject: [PATCH 150/263] Fix "lib/debug/session.rb:2527: warning: assigned but unused variable - sym" --- lib/debug/session.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 6a838eec0..191b4e4fd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2538,7 +2538,7 @@ def trap sig, *command, &command_proc sig end - case sig&.to_s&.to_sym + case sym when :INT, :SIGINT if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint? return SESSION.save_int_trap(command.empty? ? command_proc : command.first) From 840d8ad66bb638e8ee291cf6134ce63c46d38517 Mon Sep 17 00:00:00 2001 From: TSUYUSATO Kitsune Date: Mon, 12 Jun 2023 13:43:56 +0900 Subject: [PATCH 151/263] Fix a typo environeent -> environment --- test/console/control_flow_commands_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/console/control_flow_commands_test.rb b/test/console/control_flow_commands_test.rb index 6e7ff98da..de19c267b 100644 --- a/test/console/control_flow_commands_test.rb +++ b/test/console/control_flow_commands_test.rb @@ -226,7 +226,7 @@ def test_finish end def test_finish_0 - omit "This test failed with only reline environeent. It may be bug of Reline" unless defined?(Readline) + omit "This test failed with only reline environment. It may be bug of Reline" unless defined?(Readline) debug_code program do type 'b 8' From 4e70b1770bf3ef60eb20589bad176e0cdbb557f9 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Mon, 2 Oct 2023 21:04:12 +0100 Subject: [PATCH 152/263] Drop patch for Reline 0.2.7 The original issue in Reline has been fixed in https://github.com/ruby/reline/pull/358 and was released in Reline 0.2.8+. Consider `debug` currently requires Reline 0.3.8+, we won't need this patch anymore. --- lib/debug/console.rb | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index 959b940e4..53545e5e9 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -5,30 +5,9 @@ class Console raise LoadError if CONFIG[:no_reline] require 'reline' - # reline 0.2.7 or later is required. - raise LoadError if Reline::VERSION < '0.2.7' - require_relative 'color' - include Color - - begin - prev = trap(:SIGWINCH, nil) - trap(:SIGWINCH, prev) - SIGWINCH_SUPPORTED = true - rescue ArgumentError - SIGWINCH_SUPPORTED = false - end - # 0.2.7 has SIGWINCH issue on non-main thread - class ::Reline::LineEditor - m = Module.new do - def reset(prompt = '', encoding:) - super - Signal.trap(:SIGWINCH, nil) - end - end - prepend m - end if SIGWINCH_SUPPORTED + include Color def parse_input buff, commands c, rest = get_command buff From dea10b50f2ca65ab3401ef28961b960cd087f98f Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 17 Aug 2023 22:29:08 +0100 Subject: [PATCH 153/263] Allow TracePoint reentry during DAP's evaluation This avoids the TracePoint conflict with Zeitwerk, which was reported in https://github.com/ruby/debug/issues/408 --- lib/debug/server_dap.rb | 4 ++- test/protocol/break_test.rb | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 8dbefda8a..87c22ca45 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -788,7 +788,9 @@ def value_inspect obj, short: true def dap_eval b, expr, _context, prompt: '(repl_eval)' begin - b.eval(expr.to_s, prompt) + tp_allow_reentry do + b.eval(expr.to_s, prompt) + end rescue Exception => e e end diff --git a/test/protocol/break_test.rb b/test/protocol/break_test.rb index 30ad2025d..a78f70ebd 100644 --- a/test/protocol/break_test.rb +++ b/test/protocol/break_test.rb @@ -83,4 +83,56 @@ def test_break_stops_at_the_extra_file end end end + + class NestedBreakTest < ProtocolTestCase + PROGRAM = <<~RUBY + 1| def foo(x) + 2| x + 3| end + 4| + 5| foo("foo") + RUBY + + def test_breakpoint_can_be_triggered_inside_suspenssion + run_protocol_scenario PROGRAM, cdp: false do + req_add_breakpoint 2 + req_continue + assert_line_num 2 + + assert_locals_result( + [ + { name: "%self", value: "main", type: "Object" }, + { name: "x", value: "foo", type: "String" }, + ] + ) + + # Only if TracePoint.allow_reentry is available, we can trigger TracePoint events + # inside another TracePoint event, which is essential for nested breakpoints. + if TracePoint.respond_to? :allow_reentry + evaluate("foo('bar')") + + assert_line_num 2 + assert_locals_result( + [ + { name: "%self", value: "main", type: "Object" }, + { name: "x", value: "bar", type: "String" }, + ] + ) + end + + req_terminate_debuggee + end + end + + private + + def evaluate(expression) + res = send_dap_request 'stackTrace', + threadId: 1, + startFrame: 0, + levels: 20 + f_id = res.dig(:body, :stackFrames, 0, :id) + send_request 'evaluate', expression: expression, frameId: f_id, context: "repl" + end + end end From dfa817e9033f6847ab68013b2b3944391fd8469d Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 22 Oct 2023 21:26:50 +0900 Subject: [PATCH 154/263] Add debuggerId field in the RETURN OBJECT of "Debugger.enable --- lib/debug/server_cdp.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index ef556febd..397703aa6 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -474,7 +474,7 @@ def process when 'Debugger.getScriptSource' @q_msg << req when 'Debugger.enable' - send_response req + send_response req, debuggerId: rand.to_s @q_msg << req when 'Runtime.enable' send_response req From b8f2fdf7afe7dc7bb5c7fb96aae8a94280828489 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 22 Oct 2023 21:37:30 +0900 Subject: [PATCH 155/263] CDP: disable JavaScript engine based autocompletion --- lib/debug/server.rb | 2 +- lib/debug/server_cdp.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/server.rb b/lib/debug/server.rb index a67922ac1..7141ce295 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -410,7 +410,7 @@ def chrome_setup DEBUGGER__.warn <<~EOS With Chrome browser, type the following URL in the address-bar: - devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid} + devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&noJavaScriptCompletion=true&ws=#{@local_addr.inspect_sockaddr}/#{@uuid} EOS end diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 397703aa6..d4e012fe2 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -59,7 +59,7 @@ def setup_chrome addr, uuid ws_client.send sessionId: s_id, id: 5, method: 'Page.navigate', params: { - url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}", + url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&noJavaScriptCompletion=true&ws=#{addr}/#{uuid}", frameId: f_id } when 101 From 3255b7124a0abe20c780f5ae7fba11c3ff690de3 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 26 Oct 2023 20:30:30 +0100 Subject: [PATCH 156/263] Unfreeze threads for object-evaluating commands There are several commands that evaluate objects and call methods on them, such as: - info - ls (outline) - trace object - display If the called method acquires a mutex shared with another thread (e.g. when using Timeout), then it'd cause a deadlock as all threads are stopped. For example, if there's an ActiveRecord Relation object stored as a local variable, and the user runs the `info` command, then it'd call `inspect` on it and trigger a database query, it could cause a deadlock as described in #877. This commit fixes the issue by unfreezing all threads before evaluating those commands and freezing them again after receiving the result event. --- lib/debug/session.rb | 32 +++++++++++++++++++------------- test/console/info_test.rb | 32 ++++++++++++++++++++++++++++++++ test/console/outline_test.rb | 31 +++++++++++++++++++++++++++++++ test/console/trace_test.rb | 32 +++++++++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 14 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 191b4e4fd..7e1bf5a55 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -256,6 +256,11 @@ def request_tc(req) @tc << req end + def request_tc_with_freed_threads(req) + restart_all_threads + request_tc(req) + end + def process_event evt # variable `@internal_info` is only used for test tc, output, ev, @internal_info, *ev_args = evt @@ -314,7 +319,7 @@ def process_event evt if @displays.empty? wait_command_loop else - request_tc [:eval, :display, @displays] + request_eval :display, @displays end when :result raise "[BUG] not in subsession" if @subsession_stack.empty? @@ -329,6 +334,7 @@ def process_event evt end end + stop_all_threads when :method_breakpoint, :watch_breakpoint bp = ev_args[1] if bp @@ -342,6 +348,7 @@ def process_event evt obj_inspect = ev_args[2] opt = ev_args[3] add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt) + stop_all_threads else stop_all_threads end @@ -810,15 +817,15 @@ def register_default_command case sub when nil - request_tc [:show, :default, pat] # something useful + request_tc_with_freed_threads [:show, :default, pat] # something useful when :locals - request_tc [:show, :locals, pat] + request_tc_with_freed_threads [:show, :locals, pat] when :ivars - request_tc [:show, :ivars, pat, opt] + request_tc_with_freed_threads [:show, :ivars, pat, opt] when :consts - request_tc [:show, :consts, pat, opt] + request_tc_with_freed_threads [:show, :consts, pat, opt] when :globals - request_tc [:show, :globals, pat] + request_tc_with_freed_threads [:show, :globals, pat] when :threads thread_list :retry @@ -838,7 +845,7 @@ def register_default_command # * Show you available methods and instance variables of the given object. # * If the object is a class/module, it also lists its constants. register_command 'outline', 'o', 'ls', unsafe: false do |arg| - request_tc [:show, :outline, arg] + request_tc_with_freed_threads [:show, :outline, arg] end # * `display` @@ -848,9 +855,9 @@ def register_default_command register_command 'display', postmortem: false do |arg| if arg && !arg.empty? @displays << arg - request_tc [:eval, :try_display, @displays] + request_eval :try_display, @displays else - request_tc [:eval, :display, @displays] + request_eval :display, @displays end end @@ -864,7 +871,7 @@ def register_default_command if @displays[n = $1.to_i] @displays.delete_at n end - request_tc [:eval, :display, @displays] + request_eval :display, @displays when nil if ask "clear all?", 'N' @displays.clear @@ -983,7 +990,7 @@ def register_default_command :retry when /\Aobject\s+(.+)/ - request_tc [:trace, :object, $1.strip, {pattern: pattern, into: into}] + request_tc_with_freed_threads [:trace, :object, $1.strip, {pattern: pattern, into: into}] when /\Aoff\s+(\d+)\z/ if t = @tracers.values[$1.to_i] @@ -1165,8 +1172,7 @@ def process_command line end def request_eval type, src - restart_all_threads - request_tc [:eval, type, src] + request_tc_with_freed_threads [:eval, type, src] end def step_command type, arg diff --git a/test/console/info_test.rb b/test/console/info_test.rb index c14fe5991..85508dd70 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -367,4 +367,36 @@ def test_ivar_abbrev end end end + + class InfoThreadLockingTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| $m = Mutex.new + 3| th1 = Thread.new do + 4| $m.lock + 5| sleep 1 + 6| $m.unlock + 7| end + 8| + 9| o = Object.new + 10| def o.inspect + 11| $m.lock + 12| "foo" + 13| end + 14| + 15| sleep 0.5 + 16| debugger + RUBY + end + + def test_info_doesnt_cause_deadlock + debug_code(program) do + type 'c' + type 'info' + assert_line_text(/%self = main/) + type 'c' + end + end + end end diff --git a/test/console/outline_test.rb b/test/console/outline_test.rb index f86350399..73b9a5481 100644 --- a/test/console/outline_test.rb +++ b/test/console/outline_test.rb @@ -67,4 +67,35 @@ def test_outline_aliases end end end + + class OutlineThreadLockingTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| $m = Mutex.new + 3| th1 = Thread.new do + 4| $m.lock + 5| sleep 1 + 6| $m.unlock + 7| end + 8| + 9| def self.constants # overriding constants is only one of the ways to cause deadlock with outline + 10| $m.lock + 11| [] + 12| end + 13| + 14| sleep 0.5 + 15| debugger + RUBY + end + + def test_outline_doesnt_cause_deadlock + debug_code(program) do + type 'c' + type 'ls' + assert_line_text(/locals: th0/) + type 'c' + end + end + end end diff --git a/test/console/trace_test.rb b/test/console/trace_test.rb index 71629e797..68e1df260 100644 --- a/test/console/trace_test.rb +++ b/test/console/trace_test.rb @@ -473,6 +473,36 @@ def test_block_doesnt_break_tracer end end + class ThreadLockingTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| $m = Mutex.new + 3| th1 = Thread.new do + 4| $m.lock + 5| sleep 1 + 6| $m.unlock + 7| end + 8| + 9| def inspect + 10| m.lock + 11| "" + 12| end + 13| + 14| sleep 0.5 + 15| debugger + RUBY + end + + def test_object_tracer_doesnt_cause_deadlock + debug_code(program) do + type 'c' + type 'trace object self' + type 'c' + end + end + end + class TraceCallReceiverTest < ConsoleTestCase def program <<~RUBY @@ -544,7 +574,7 @@ def program 6| p a RUBY end - + def test_1656237686 debug_code(program) do type 'trace line' From 2e130ff573003f3fe1bf76325d66485b172ffd50 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 11 Nov 2023 16:44:16 +0900 Subject: [PATCH 157/263] rename method. `request_tc_with_freed_threads` -> `request_tc_with_restarted_threads` because `freed` is ambiguous (with memory management). --- lib/debug/session.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 7e1bf5a55..3db2f45da 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -256,11 +256,15 @@ def request_tc(req) @tc << req end - def request_tc_with_freed_threads(req) + def request_tc_with_restarted_threads(req) restart_all_threads request_tc(req) end + def request_eval type, src + request_tc_with_restarted_threads [:eval, type, src] + end + def process_event evt # variable `@internal_info` is only used for test tc, output, ev, @internal_info, *ev_args = evt @@ -817,15 +821,15 @@ def register_default_command case sub when nil - request_tc_with_freed_threads [:show, :default, pat] # something useful + request_tc_with_restarted_threads [:show, :default, pat] # something useful when :locals - request_tc_with_freed_threads [:show, :locals, pat] + request_tc_with_restarted_threads [:show, :locals, pat] when :ivars - request_tc_with_freed_threads [:show, :ivars, pat, opt] + request_tc_with_restarted_threads [:show, :ivars, pat, opt] when :consts - request_tc_with_freed_threads [:show, :consts, pat, opt] + request_tc_with_restarted_threads [:show, :consts, pat, opt] when :globals - request_tc_with_freed_threads [:show, :globals, pat] + request_tc_with_restarted_threads [:show, :globals, pat] when :threads thread_list :retry @@ -845,7 +849,7 @@ def register_default_command # * Show you available methods and instance variables of the given object. # * If the object is a class/module, it also lists its constants. register_command 'outline', 'o', 'ls', unsafe: false do |arg| - request_tc_with_freed_threads [:show, :outline, arg] + request_tc_with_restarted_threads [:show, :outline, arg] end # * `display` @@ -990,7 +994,7 @@ def register_default_command :retry when /\Aobject\s+(.+)/ - request_tc_with_freed_threads [:trace, :object, $1.strip, {pattern: pattern, into: into}] + request_tc_with_restarted_threads [:trace, :object, $1.strip, {pattern: pattern, into: into}] when /\Aoff\s+(\d+)\z/ if t = @tracers.values[$1.to_i] @@ -1171,10 +1175,6 @@ def process_command line return :retry end - def request_eval type, src - request_tc_with_freed_threads [:eval, type, src] - end - def step_command type, arg if type == :until leave_subsession [:step, type, arg] From c3d5e8cc41916544f80e424d3d92b9a7a6586fdf Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Nov 2023 07:31:41 +0900 Subject: [PATCH 158/263] Do not use HEAD request if 1 port If there is only one opening debug port with UNIX domain socket, no need to use HEAD request. Before: ``` $ exe/rdbg -O target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/ruby-debug-ko1-223816) DEBUGGER: wait for debugger connection... DEBUGGER: Connected. DEBUGGER: GreetingError: HEAD request DEBUGGER: Disconnected. DEBUGGER: Connected. ``` After: ``` $ exe/rdbg -O target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/ruby-debug-ko1-223984) DEBUGGER: wait for debugger connection... DEBUGGER: Connected. ``` --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby.yml | 2 +- README.md | 1 + debug.gemspec | 4 ++-- lib/debug/client.rb | 5 +++-- lib/debug/config.rb | 1 + lib/debug/session.rb | 5 +++++ lib/debug/thread_client.rb | 9 ++------- test/support/console_test_case.rb | 1 + 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index b2889aab1..4225bd934 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head', 'debug'] + ruby-version: ["2.7", "3.0", "3.1", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index a41da836a..8f8685665 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] + ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index c46a5d058..6edabe520 100644 --- a/README.md +++ b/README.md @@ -477,6 +477,7 @@ config set no_color true * `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false) * `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false) * `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false) + * `RUBY_DEBUG_IRB_CONSOLE` (`irb_console`): Use IRB as the console (default: false) * CONTROL * `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths diff --git a/debug.gemspec b/debug.gemspec index a07018a77..03ed0584f 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the ancient Ruby versions.} spec.homepage = "https://github.com/ruby/debug" spec.licenses = ["Ruby", "BSD-2-Clause"] - spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") + spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0") spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage @@ -27,6 +27,6 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.extensions = ['ext/debug/extconf.rb'] - spec.add_dependency "irb", ">= 1.5.0" # for binding.irb(show_code: false) + spec.add_dependency "irb", ">= 1.8.3" # for irb:debug integration spec.add_dependency "reline", ">= 0.3.8" end diff --git a/lib/debug/client.rb b/lib/debug/client.rb index 2d7d31b56..a801d3502 100644 --- a/lib/debug/client.rb +++ b/lib/debug/client.rb @@ -165,15 +165,16 @@ def connect_unix name = nil end else Client.cleanup_unix_domain_sockets - files = Client.list_connections verbose: true + files = Client.list_connections case files.size when 0 $stderr.puts "No debug session is available." exit when 1 - @s = Socket.unix(files.first.first) + @s = Socket.unix(files.first) else + files = Client.list_connections verbose: true $stderr.puts "Please select a debug session:" files.each{|(f, desc)| $stderr.puts " #{File.basename(f)} (#{desc})" diff --git a/lib/debug/config.rb b/lib/debug/config.rb index f6f1a066d..af557a0cf 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -22,6 +22,7 @@ module DEBUGGER__ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], + irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3db2f45da..cb3e85fcd 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -202,6 +202,11 @@ def activate ui = nil, on_fork: false end @tp_thread_end.enable + if CONFIG[:irb_console] + require_relative "irb_integration" + thc.activate_irb_integration + end + # session start q << true session_server_main diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 3ec53fb81..6f9da4af1 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1048,13 +1048,8 @@ def wait_next_action_ when :call result = frame_eval(eval_src) when :irb - require 'irb' # prelude's binding.irb doesn't have show_code option - begin - result = frame_eval('binding.irb(show_code: false)', binding_location: true) - ensure - # workaround: https://github.com/ruby/debug/issues/308 - Reline.prompt_proc = nil if defined? Reline - end + require_relative "irb_integration" + activate_irb_integration when :display, :try_display failed_results = [] eval_src.each_with_index{|src, i| diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 49e0bb87f..efdc1bafe 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -217,6 +217,7 @@ def prepare_test_environment(program, test_steps, &block) ENV['RUBY_DEBUG_TEST_UI'] = 'terminal' ENV['RUBY_DEBUG_NO_RELINE'] = 'true' ENV['RUBY_DEBUG_HISTORY_FILE'] = '' + ENV['TERM'] = 'dumb' write_temp_file(strip_line_num(program)) @scenario = [] From 5b47f6aa8f7ec1d8e869ffcc249c83922a90e2e2 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Nov 2023 17:22:56 +0900 Subject: [PATCH 159/263] Revert "Do not use HEAD request if 1 port" This reverts commit 6571e2a46b054c8c81dcefc19094eec1767462f9. It contains #1024 accidentally. --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby.yml | 2 +- README.md | 1 - debug.gemspec | 4 ++-- lib/debug/client.rb | 5 ++--- lib/debug/config.rb | 1 - lib/debug/session.rb | 5 ----- lib/debug/thread_client.rb | 9 +++++++-- test/support/console_test_case.rb | 1 - 9 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 4225bd934..b2889aab1 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "head", "debug"] + ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head', 'debug'] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8f8685665..a41da836a 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] + ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index 6edabe520..c46a5d058 100644 --- a/README.md +++ b/README.md @@ -477,7 +477,6 @@ config set no_color true * `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false) * `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false) * `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false) - * `RUBY_DEBUG_IRB_CONSOLE` (`irb_console`): Use IRB as the console (default: false) * CONTROL * `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths diff --git a/debug.gemspec b/debug.gemspec index 03ed0584f..a07018a77 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the ancient Ruby versions.} spec.homepage = "https://github.com/ruby/debug" spec.licenses = ["Ruby", "BSD-2-Clause"] - spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0") + spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage @@ -27,6 +27,6 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.extensions = ['ext/debug/extconf.rb'] - spec.add_dependency "irb", ">= 1.8.3" # for irb:debug integration + spec.add_dependency "irb", ">= 1.5.0" # for binding.irb(show_code: false) spec.add_dependency "reline", ">= 0.3.8" end diff --git a/lib/debug/client.rb b/lib/debug/client.rb index a801d3502..2d7d31b56 100644 --- a/lib/debug/client.rb +++ b/lib/debug/client.rb @@ -165,16 +165,15 @@ def connect_unix name = nil end else Client.cleanup_unix_domain_sockets - files = Client.list_connections + files = Client.list_connections verbose: true case files.size when 0 $stderr.puts "No debug session is available." exit when 1 - @s = Socket.unix(files.first) + @s = Socket.unix(files.first.first) else - files = Client.list_connections verbose: true $stderr.puts "Please select a debug session:" files.each{|(f, desc)| $stderr.puts " #{File.basename(f)} (#{desc})" diff --git a/lib/debug/config.rb b/lib/debug/config.rb index af557a0cf..f6f1a066d 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -22,7 +22,6 @@ module DEBUGGER__ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], - irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], diff --git a/lib/debug/session.rb b/lib/debug/session.rb index cb3e85fcd..3db2f45da 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -202,11 +202,6 @@ def activate ui = nil, on_fork: false end @tp_thread_end.enable - if CONFIG[:irb_console] - require_relative "irb_integration" - thc.activate_irb_integration - end - # session start q << true session_server_main diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 6f9da4af1..3ec53fb81 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1048,8 +1048,13 @@ def wait_next_action_ when :call result = frame_eval(eval_src) when :irb - require_relative "irb_integration" - activate_irb_integration + require 'irb' # prelude's binding.irb doesn't have show_code option + begin + result = frame_eval('binding.irb(show_code: false)', binding_location: true) + ensure + # workaround: https://github.com/ruby/debug/issues/308 + Reline.prompt_proc = nil if defined? Reline + end when :display, :try_display failed_results = [] eval_src.each_with_index{|src, i| diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index efdc1bafe..49e0bb87f 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -217,7 +217,6 @@ def prepare_test_environment(program, test_steps, &block) ENV['RUBY_DEBUG_TEST_UI'] = 'terminal' ENV['RUBY_DEBUG_NO_RELINE'] = 'true' ENV['RUBY_DEBUG_HISTORY_FILE'] = '' - ENV['TERM'] = 'dumb' write_temp_file(strip_line_num(program)) @scenario = [] From 695500fd78ee94186fe5438ed80084dd2f890ac6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Nov 2023 17:31:27 +0900 Subject: [PATCH 160/263] Do not use HEAD request if 1 port If there is only one opening debug port with UNIX domain socket, no need to use HEAD request. Before: ``` $ exe/rdbg -O target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/ruby-debug-ko1-223816) DEBUGGER: wait for debugger connection... DEBUGGER: Connected. DEBUGGER: GreetingError: HEAD request DEBUGGER: Disconnected. DEBUGGER: Connected. ``` After: ``` $ exe/rdbg -O target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/ruby-debug-ko1-223984) DEBUGGER: wait for debugger connection... DEBUGGER: Connected. ``` --- lib/debug/client.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/debug/client.rb b/lib/debug/client.rb index 2d7d31b56..a801d3502 100644 --- a/lib/debug/client.rb +++ b/lib/debug/client.rb @@ -165,15 +165,16 @@ def connect_unix name = nil end else Client.cleanup_unix_domain_sockets - files = Client.list_connections verbose: true + files = Client.list_connections case files.size when 0 $stderr.puts "No debug session is available." exit when 1 - @s = Socket.unix(files.first.first) + @s = Socket.unix(files.first) else + files = Client.list_connections verbose: true $stderr.puts "Please select a debug session:" files.each{|(f, desc)| $stderr.puts " #{File.basename(f)} (#{desc})" From b719b3eb28ab07b11aa2b3537ca51b61df1ca7af Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Nov 2023 18:01:45 +0900 Subject: [PATCH 161/263] shorten UNIX domain socket name to allow adding session name. --- lib/debug/config.rb | 7 +++---- test/console/client_test.rb | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index f6f1a066d..ad07a017d 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -458,7 +458,7 @@ def self.unix_domain_socket_tmpdir require 'tmpdir' if tmpdir = Dir.tmpdir - path = File.join(tmpdir, "ruby-debug-sock-#{Process.uid}") + path = File.join(tmpdir, "rdbg-#{Process.uid}") unless File.exist?(path) d = Dir.mktmpdir @@ -471,7 +471,7 @@ def self.unix_domain_socket_tmpdir def self.unix_domain_socket_homedir if home = ENV['HOME'] - path = File.join(home, '.ruby-debug-sock') + path = File.join(home, '.rdbg-sock') unless File.exist?(path) Dir.mkdir(path, 0700) @@ -495,8 +495,7 @@ def self.unix_domain_socket_dir end def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir) - user = ENV['USER'] || 'UnknownUser' - File.join(base_dir, "ruby-debug-#{user}") + File.join(base_dir, "rdbg") end def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir) diff --git a/test/console/client_test.rb b/test/console/client_test.rb index 9b31af0c2..31432291d 100644 --- a/test/console/client_test.rb +++ b/test/console/client_test.rb @@ -10,7 +10,7 @@ def test_gen_sockpath Client.util("gen-sockpath") end - assert_match(/ruby-debug-/, output) + assert_match(/rdbg-/, output) end def test_list_socks @@ -19,7 +19,7 @@ def test_list_socks end unless output.empty? - assert_match(/ruby-debug-/, output) + assert_match(/rdbg-/, output) end end From 5c33af4d766ea870ccaade1a2e24b63f7ae10ac6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 14 Nov 2023 18:04:49 +0900 Subject: [PATCH 162/263] `session_name` config to allow multiple debug sessions. Now session name is used to name UNIX domain socket file name. ``` $ exe/rdbg -O target.rb --session-name=hoge DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/rdbg-230122-hoge) ``` ``` $ RUBY_DEBUG_SESSION_NAME=fuga exe/rdbg -O target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/run/user/1000/rdbg-230150-fuga) ``` Co-authored-by: Andy Jeffries --- README.md | 2 ++ lib/debug/config.rb | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c46a5d058..f47914053 100644 --- a/README.md +++ b/README.md @@ -504,6 +504,7 @@ config set no_color true * `RUBY_DEBUG_LOCAL_FS_MAP` (`local_fs_map`): Specify local fs map * `RUBY_DEBUG_SKIP_BP` (`skip_bp`): Skip breakpoints if no clients are attached (default: false) * `RUBY_DEBUG_COOKIE` (`cookie`): Cookie for negotiation + * `RUBY_DEBUG_SESSION_NAME` (`session_name`): Session name for differentiating multiple sessions * `RUBY_DEBUG_CHROME_PATH` (`chrome_path`): Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64)) * OBSOLETE @@ -883,6 +884,7 @@ Debug console mode: --port=PORT Listening TCP/IP port --host=HOST Listening TCP/IP host --cookie=COOKIE Set a cookie for connection + --session-name=NAME Session name Debug console mode runs Ruby program with the debug console. diff --git a/lib/debug/config.rb b/lib/debug/config.rb index ad07a017d..e954b56bf 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -49,6 +49,7 @@ module DEBUGGER__ local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map], skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'], cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"], + session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"], chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"], # obsolete @@ -340,6 +341,9 @@ def self.parse_argv argv o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c| config[:cookie] = c end + o.on('--session-name=NAME', 'Session name') do |name| + config[:session_name] = name + end rdbg = 'rdbg' @@ -499,7 +503,10 @@ def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir end def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir) - create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}" + suffix = "-#{Process.pid}" + name = CONFIG[:session_name] + suffix << "-#{name}" if name + create_unix_domain_socket_name_prefix(base_dir) + suffix end ## Help From 4e2bd2555bdab0508c1b3301d2fcf076c9ccc844 Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Thu, 23 Nov 2023 15:31:44 -0500 Subject: [PATCH 163/263] Prevent backtrace from hanging if objects in the backtrace use Thread in inspect Co-authored-by: Stan Lo --- lib/debug/session.rb | 8 +++---- test/console/backtrace_test.rb | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3db2f45da..321ba8231 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -696,15 +696,15 @@ def register_default_command register_command 'bt', 'backtrace', unsafe: false do |arg| case arg when /\A(\d+)\z/ - request_tc [:show, :backtrace, arg.to_i, nil] + request_tc_with_restarted_threads [:show, :backtrace, arg.to_i, nil] when /\A\/(.*)\/\z/ pattern = $1 - request_tc [:show, :backtrace, nil, Regexp.compile(pattern)] + request_tc_with_restarted_threads [:show, :backtrace, nil, Regexp.compile(pattern)] when /\A(\d+)\s+\/(.*)\/\z/ max, pattern = $1, $2 - request_tc [:show, :backtrace, max.to_i, Regexp.compile(pattern)] + request_tc_with_restarted_threads [:show, :backtrace, max.to_i, Regexp.compile(pattern)] else - request_tc [:show, :backtrace, nil, nil] + request_tc_with_restarted_threads [:show, :backtrace, nil, nil] end end diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index dd1316ee5..3fcdf81ee 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -188,4 +188,45 @@ def test_backtrace_prints_nested_block_label_correctly end end end + + class ThreadLockingTraceTest < ConsoleTestCase + def program + <<~RUBY + 1| th0 = Thread.new{sleep} + 2| $m = Mutex.new + 3| th1 = Thread.new do + 4| $m.lock + 5| sleep 1 + 6| $m.unlock + 7| end + 8| + 9| o = Object.new + 10| def o.inspect + 11| $m.lock + 12| "foo".tap { $m.unlock } + 13| end + 14| + 15| def foo(o) + 16| debugger + 17| end + 18| sleep 0.5 + 19| foo(o) + RUBY + end + + def test_backtrace_prints_without_hanging + debug_code(program) do + type "c" + + type "bt" + assert_line_text(/Object#foo\(o=foo\)/) + type "bt" + assert_line_text(/Object#foo\(o=foo\)/) + type "bt" + assert_line_text(/Object#foo\(o=foo\)/) + + type "kill!" + end + end + end end From cbd0f71c83e464027acedd89e807e0176a22735b Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 15 Nov 2023 00:02:11 +0900 Subject: [PATCH 164/263] Show session_name on connection On HEAD request and attaching, show session name if available. --- lib/debug/server.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 7141ce295..0915b5bd5 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -133,7 +133,7 @@ def greeting require 'etc' check_cookie $1 - @sock.puts "PID: #{Process.pid}, $0: #{$0}" + @sock.puts "PID: #{Process.pid}, $0: #{$0}, session_name: #{CONFIG[:session_name]}" @sock.puts "debug #{VERSION} on #{RUBY_DESCRIPTION}" @sock.puts "uname: #{Etc.uname.inspect}" @sock.close @@ -149,7 +149,9 @@ def greeting end parse_option(params) - puts "DEBUGGER (client): Connected. PID:#{Process.pid}, $0:#{$0}" + session_name = CONFIG[:session_name] + session_name_str = ", session_name:#{session_name}" if session_name + puts "DEBUGGER (client): Connected. PID:#{Process.pid}, $0:#{$0}#{session_name_str}" puts "DEBUGGER (client): Type `Ctrl-C` to enter the debug console." unless @need_pause_at_first puts From 233c4a0d9e80a587c890e0e96714e37c2c29eb21 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 28 Nov 2023 12:10:33 +0100 Subject: [PATCH 165/263] Cleanup workflows: remove workflow example text --- .github/workflows/protocol.yml | 11 +---------- .github/workflows/ruby-macos.yaml | 11 +---------- .github/workflows/ruby.yml | 11 +---------- .github/workflows/test_test.yml | 11 +---------- 4 files changed, 4 insertions(+), 40 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index b2889aab1..0629e922b 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -1,10 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - name: Protocol on: @@ -26,12 +19,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Ruby - # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, - # change this to (see https://github.com/ruby/setup-ruby#versioning): uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler-cache: true - name: Run tests run: | bundle exec rake clobber diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 0274941df..e13e52b6c 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -1,10 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - name: Ruby(macOS) on: @@ -26,12 +19,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Ruby - # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, - # change this to (see https://github.com/ruby/setup-ruby#versioning): uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler-cache: true - name: Run tests run: | bundle exec rake clobber diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index a41da836a..207d52199 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -1,10 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - name: Ruby on: @@ -26,12 +19,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Ruby - # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, - # change this to (see https://github.com/ruby/setup-ruby#versioning): uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler-cache: true - name: Run tests run: | bundle exec rake clobber diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index db4cb9e95..e65ded2bf 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -1,10 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake -# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby - name: TestTestFramework on: @@ -26,12 +19,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Ruby - # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, - # change this to (see https://github.com/ruby/setup-ruby#versioning): uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + bundler-cache: true - name: Run tests run: | bundle exec rake clobber From 5d98691e3659dc539d473fd7a922ec2263284ffd Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 28 Nov 2023 12:02:58 +0100 Subject: [PATCH 166/263] Compile iseq_collector.c logic only on CRuby MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * iseq_collector.c relies on many CRuby internals, there is no point to compile it on other Rubies. * It now fails to compile on TruffleRuby: ../../../../ext/debug/iseq_collector.c: In function ‘imemo_type’: ../../../../ext/debug/iseq_collector.c:18:13: error: implicit declaration of function ‘RBASIC’ [-Werror=implicit-function-declaration] 18 | return (RBASIC(imemo)->flags >> FL_USHIFT) & imemo_mask; | ^~~~~~ --- ext/debug/debug.c | 6 ++++++ ext/debug/extconf.rb | 1 + ext/debug/iseq_collector.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index 9eaac2bbd..d7bb3e2ab 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -180,13 +180,17 @@ iseq_last_line(VALUE iseqw) } #endif +#ifdef HAVE_RB_ISEQ void Init_iseq_collector(void); +#endif void Init_debug(void) { +#ifdef HAVE_RB_ISEQ VALUE rb_mRubyVM = rb_const_get(rb_cObject, rb_intern("RubyVM")); VALUE rb_cISeq = rb_const_get(rb_mRubyVM, rb_intern("InstructionSequence")); +#endif rb_mDebugger = rb_const_get(rb_cObject, rb_intern("DEBUGGER__")); rb_cFrameInfo = rb_const_get(rb_mDebugger, rb_intern("FrameInfo")); @@ -210,5 +214,7 @@ Init_debug(void) rb_define_method(rb_cISeq, "last_line", iseq_last_line, 0); #endif +#ifdef HAVE_RB_ISEQ Init_iseq_collector(); +#endif } diff --git a/ext/debug/extconf.rb b/ext/debug/extconf.rb index b4e78fbe3..9c4f5417a 100644 --- a/ext/debug/extconf.rb +++ b/ext/debug/extconf.rb @@ -4,6 +4,7 @@ $distcleanfiles << "debug_version.h" if defined? RubyVM + $defs << '-DHAVE_RB_ISEQ' $defs << '-DHAVE_RB_ISEQ_PARAMETERS' $defs << '-DHAVE_RB_ISEQ_CODE_LOCATION' diff --git a/ext/debug/iseq_collector.c b/ext/debug/iseq_collector.c index f87c4f978..ae0beb487 100644 --- a/ext/debug/iseq_collector.c +++ b/ext/debug/iseq_collector.c @@ -1,5 +1,6 @@ #include +#ifdef HAVE_RB_ISEQ VALUE rb_iseqw_new(VALUE v); void rb_objspace_each_objects( int (*callback)(void *start, void *end, size_t stride, void *data), @@ -89,3 +90,4 @@ Init_iseq_collector(void) rb_define_singleton_method(rb_mObjSpace, "each_iseq", each_iseq, 0); rb_define_singleton_method(rb_mObjSpace, "count_iseq", count_iseq, 0); } +#endif From 685caf173ac270ff66ec970acd712b2b896b4bca Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 28 Nov 2023 12:08:21 +0100 Subject: [PATCH 167/263] Add a workflow to ensure the gem builds fine on TruffleRuby --- .github/workflows/truffleruby.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/truffleruby.yml diff --git a/.github/workflows/truffleruby.yml b/.github/workflows/truffleruby.yml new file mode 100644 index 000000000..2d05d2ce7 --- /dev/null +++ b/.github/workflows/truffleruby.yml @@ -0,0 +1,24 @@ +name: TruffleRuby + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + truffleruby: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: truffleruby-head + bundler-cache: true + - name: Test installing the gem on TruffleRuby + run: | + bundle exec rake compile + bundle exec rake build + gem install pkg/debug-*.gem From f1042b740c91e9d0efe54158b6c17e490f56c686 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 28 Nov 2023 13:36:50 +0100 Subject: [PATCH 168/263] Check if RubyVM is defined before accessing it --- lib/debug/session.rb | 4 ++-- lib/debug/source_repository.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 321ba8231..86834cf61 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -82,7 +82,7 @@ def last_line def first_line self.to_a[4][:code_location][0] end unless method_defined?(:first_line) -end +end if defined?(RubyVM::InstructionSequence) module DEBUGGER__ PresetCommands = Struct.new(:commands, :source, :auto_continue) @@ -133,7 +133,7 @@ def initialize @commands = {} @unsafe_context = false - @has_keep_script_lines = RubyVM.respond_to? :keep_script_lines + @has_keep_script_lines = defined?(RubyVM.keep_script_lines) @tp_load_script = TracePoint.new(:script_compiled){|tp| eval_script = tp.eval_script unless @has_keep_script_lines diff --git a/lib/debug/source_repository.rb b/lib/debug/source_repository.rb index ddcfd6e93..52e43cf7d 100644 --- a/lib/debug/source_repository.rb +++ b/lib/debug/source_repository.rb @@ -22,7 +22,7 @@ def get iseq end end - if RubyVM.respond_to? :keep_script_lines + if defined?(RubyVM.keep_script_lines) # Ruby 3.1 and later RubyVM.keep_script_lines = true require 'objspace' From 9d1b479e1a36e3da086919361df9b3dd604e7d7c Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Mon, 9 Oct 2023 13:05:51 +0100 Subject: [PATCH 169/263] Upgrade the irb command to use irb:debug integration This means that user will get an IRB session that has access to the debug commands too by activating IRB's debug integration automatically: https://github.com/ruby/irb#debugging-with-irb --- debug.gemspec | 2 +- lib/debug/irb_integration.rb | 27 +++++++++++++++++++ lib/debug/session.rb | 5 ++-- lib/debug/thread_client.rb | 9 ++----- test/console/irb_test.rb | 45 +++++++++++++++++++++++++++++++ test/support/console_test_case.rb | 1 + 6 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 lib/debug/irb_integration.rb create mode 100644 test/console/irb_test.rb diff --git a/debug.gemspec b/debug.gemspec index a07018a77..7c0e2d022 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -27,6 +27,6 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.extensions = ['ext/debug/extconf.rb'] - spec.add_dependency "irb", ">= 1.5.0" # for binding.irb(show_code: false) + spec.add_dependency "irb", "~> 1.10" # for irb:debug integration spec.add_dependency "reline", ">= 0.3.8" end diff --git a/lib/debug/irb_integration.rb b/lib/debug/irb_integration.rb new file mode 100644 index 000000000..a2ea34b65 --- /dev/null +++ b/lib/debug/irb_integration.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'irb' + +module DEBUGGER__ + module IrbPatch + def evaluate(line, line_no) + SESSION.send(:restart_all_threads) + super + # This is to communicate with the test framework so it can feed the next input + puts "INTERNAL_INFO: {}" if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal' + ensure + SESSION.send(:stop_all_threads) + end + end + + class ThreadClient + def activate_irb_integration + IRB.setup(location, argv: []) + workspace = IRB::WorkSpace.new(current_frame&.binding || TOPLEVEL_BINDING) + irb = IRB::Irb.new(workspace) + IRB.conf[:MAIN_CONTEXT] = irb.context + IRB::Debug.setup(irb) + IRB::Context.prepend(IrbPatch) + end + end +end diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 86834cf61..d479135ce 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -936,10 +936,11 @@ def register_default_command # * Invoke `irb` on the current frame. register_command 'irb' do |arg| if @ui.remote? - @ui.puts "not supported on the remote console." + @ui.puts "\nIRB is supported on the remote console." :retry + else + request_eval :irb, nil end - request_eval :irb, nil end ### Trace diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 3ec53fb81..6f9da4af1 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1048,13 +1048,8 @@ def wait_next_action_ when :call result = frame_eval(eval_src) when :irb - require 'irb' # prelude's binding.irb doesn't have show_code option - begin - result = frame_eval('binding.irb(show_code: false)', binding_location: true) - ensure - # workaround: https://github.com/ruby/debug/issues/308 - Reline.prompt_proc = nil if defined? Reline - end + require_relative "irb_integration" + activate_irb_integration when :display, :try_display failed_results = [] eval_src.each_with_index{|src, i| diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb new file mode 100644 index 000000000..e8dd61d0f --- /dev/null +++ b/test/console/irb_test.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require_relative '../support/console_test_case' + +module DEBUGGER__ + class IrbTest < ConsoleTestCase + def setup + @original_pager = ENV["PAGER"] + ENV["PAGER"] = "cat" + end + + def teardown + ENV["PAGER"] = @original_pager + end + + def program + <<~RUBY + 1| a = 1 + 2| b = 2 + RUBY + end + + def test_irb_command_is_disabled_in_remote_mode + debug_code(program, remote: :remote_only) do + type 'irb' + assert_line_text 'IRB is supported on the remote console.' + type 'q!' + end + end + + def test_irb_command_switches_console_to_irb + debug_code(program, remote: false) do + type 'irb' + type '123' + assert_line_text 'irb:rdbg(main):002> 123' + type 'irb_info' + assert_line_text('IRB version:') + type 'next' + type 'info' + assert_line_text([/a = 1/, /b = nil/]) + type 'q!' + end + end + end +end diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 49e0bb87f..efdc1bafe 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -217,6 +217,7 @@ def prepare_test_environment(program, test_steps, &block) ENV['RUBY_DEBUG_TEST_UI'] = 'terminal' ENV['RUBY_DEBUG_NO_RELINE'] = 'true' ENV['RUBY_DEBUG_HISTORY_FILE'] = '' + ENV['TERM'] = 'dumb' write_temp_file(strip_line_num(program)) @scenario = [] From 1e59f96b09765789ee03edfd1cb18c71a1f0020d Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sat, 14 Oct 2023 15:48:34 +0100 Subject: [PATCH 170/263] Drop Ruby 2.6 support The required IRB version only supports 2.7+ --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby.yml | 2 +- README.md | 2 +- debug.gemspec | 2 +- misc/README.md.erb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 0629e922b..b29d09074 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', 'head', 'debug'] + ruby-version: ["2.7", "3.0", "3.1", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 207d52199..4662ef6a7 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'head', 'debug'] + ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/README.md b/README.md index f47914053..23318977a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # debug.rb -This library provides debugging functionality to Ruby (MRI) 2.6 and later. +This library provides debugging functionality to Ruby (MRI) 2.7 and later. This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`. New debug.rb has several advantages: diff --git a/debug.gemspec b/debug.gemspec index 7c0e2d022..2a5891f32 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |spec| spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the ancient Ruby versions.} spec.homepage = "https://github.com/ruby/debug" spec.licenses = ["Ruby", "BSD-2-Clause"] - spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") + spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0") spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage diff --git a/misc/README.md.erb b/misc/README.md.erb index 5778e5a90..ff800fabf 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -2,7 +2,7 @@ # debug.rb -This library provides debugging functionality to Ruby (MRI) 2.6 and later. +This library provides debugging functionality to Ruby (MRI) 2.7 and later. This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`. New debug.rb has several advantages: From 019d4bbb2eac45c2f95d9d7af737ed28e39ef237 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 26 Oct 2023 13:52:45 +0100 Subject: [PATCH 171/263] Support activating IRB as console with a config --- README.md | 1 + lib/debug/config.rb | 1 + lib/debug/session.rb | 5 +++++ test/console/irb_test.rb | 17 +++++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 23318977a..ddc085cd5 100644 --- a/README.md +++ b/README.md @@ -477,6 +477,7 @@ config set no_color true * `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false) * `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false) * `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false) + * `RUBY_DEBUG_IRB_CONSOLE` (`irb_console`): Use IRB as the console (default: false) * CONTROL * `RUBY_DEBUG_SKIP_PATH` (`skip_path`): Skip showing/entering frames for given paths diff --git a/lib/debug/config.rb b/lib/debug/config.rb index e954b56bf..66383c88c 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -22,6 +22,7 @@ module DEBUGGER__ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], + irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], diff --git a/lib/debug/session.rb b/lib/debug/session.rb index d479135ce..8bddae254 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -202,6 +202,11 @@ def activate ui = nil, on_fork: false end @tp_thread_end.enable + if CONFIG[:irb_console] && !CONFIG[:open] + require_relative "irb_integration" + thc.activate_irb_integration + end + # session start q << true session_server_main diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb index e8dd61d0f..533ca733f 100644 --- a/test/console/irb_test.rb +++ b/test/console/irb_test.rb @@ -41,5 +41,22 @@ def test_irb_command_switches_console_to_irb type 'q!' end end + + def test_irb_console_config_activates_irb + ENV["RUBY_DEBUG_IRB_CONSOLE"] = "true" + + debug_code(program, remote: false) do + type '123' + assert_line_text 'irb:rdbg(main):002> 123' + type 'irb_info' + assert_line_text('IRB version:') + type 'next' + type 'info' + assert_line_text([/a = 1/, /b = nil/]) + type 'q!' + end + ensure + ENV["RUBY_DEBUG_IRB_CONSOLE"] = nil + end end end From 5581994dfcc0e5e7ceccc130d2d41a9f81b28e4a Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Tue, 5 Dec 2023 18:53:30 +0000 Subject: [PATCH 172/263] Fix typo --- lib/debug/session.rb | 2 +- test/console/irb_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 8bddae254..3d973c3d2 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -941,7 +941,7 @@ def register_default_command # * Invoke `irb` on the current frame. register_command 'irb' do |arg| if @ui.remote? - @ui.puts "\nIRB is supported on the remote console." + @ui.puts "\nIRB is not supported on the remote console." :retry else request_eval :irb, nil diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb index 533ca733f..478a37036 100644 --- a/test/console/irb_test.rb +++ b/test/console/irb_test.rb @@ -23,7 +23,7 @@ def program def test_irb_command_is_disabled_in_remote_mode debug_code(program, remote: :remote_only) do type 'irb' - assert_line_text 'IRB is supported on the remote console.' + assert_line_text 'IRB is not supported on the remote console.' type 'q!' end end From 2bdb8f8186c4400d6613adadc96fa28cc064e3a2 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 6 Dec 2023 04:39:48 +0900 Subject: [PATCH 173/263] remove debug print was introduced accidentally, maybe. --- lib/debug/config.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 66383c88c..ab4c9c559 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -416,7 +416,6 @@ def self.parse_argv argv if argv.empty? case when have_shown_version && config[:mode] == :start - pp config exit end end From 90084d8e2296c0db8ddd09767054ae167c670185 Mon Sep 17 00:00:00 2001 From: Mostafa Ahangarha Date: Mon, 4 Dec 2023 15:13:59 +0330 Subject: [PATCH 174/263] Minor punctuation and grammar fixes --- README.md | 60 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index ddc085cd5..38b03a704 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This library provides debugging functionality to Ruby (MRI) 2.7 and later. -This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`. +This debug.rb is the replacement of traditional lib/debug.rb standard library, which is implemented by `set_trace_func`. New debug.rb has several advantages: * Fast: No performance penalty on non-stepping mode and non-breakpoints. @@ -18,7 +18,7 @@ New debug.rb has several advantages: Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | -* Extensible: application can introduce debugging support with several ways: +* Extensible: application can introduce debugging support in several ways: * By `rdbg` command * By loading libraries with `-r` command line option * By calling Ruby's method explicitly @@ -55,7 +55,7 @@ To use a debugger, roughly you will do the following steps: 4. Use debug commands. * [Evaluate Ruby expressions](#evaluate) (e.g. `p lvar` to see the local variable `lvar`). * [Query the program status](#information) (e.g. `info` to see information about the current frame). - * [Control program flow](#control-flow) (e.g. move to the another line with `step`, to the next line with `next`). + * [Control program flow](#control-flow) (e.g. move to another line with `step`, to the next line with `next`). * [Set another breakpoint](#breakpoint) (e.g. `catch Exception` to set a breakpoint that'll be triggered when `Exception` is raised). * [Activate tracing in your program](#trace) (e.g. `trace call` to trace method calls). * [Change the configuration](#configuration-1) (e.g. `config set no_color true` to disable coloring). @@ -238,11 +238,11 @@ d => 4 ``` By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console. -It will help that if you want to know what the program is doing. +It will help if you want to know what the program is doing. ### Use `rdbg` with commands written in Ruby -If you want to run a command written in Ruby like like `rake`, `rails`, `bundle`, `rspec` and so on, you can use `rdbg -c` option. +If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. * Without `-c` option, `rdbg ` means that `` is Ruby script and invoke it like `ruby ` with the debugger. * With `-c` option, `rdbg -c ` means that `` is command in `PATH` and simply invoke it with the debugger. @@ -265,8 +265,8 @@ Like other languages, you can use this debugger on the VSCode. 2. Open `.rb` file (e.g. `target.rb`) 3. Register breakpoints with "Toggle breakpoint" in Run menu (or type F9 key) 4. Choose "Start debugging" in "Run" menu (or type F5 key) -5. You will see a dialog "Debug command line" and you can choose your favorite command line your want to run. -6. Chosen command line is invoked with `rdbg -c` and VSCode shows the details at breakpoints. +5. You will see a dialog "Debug command line" and you can choose your favorite command line you want to run. +6. Chosen command line is invoked with `rdbg -c`, and VSCode shows the details at breakpoints. Please refer [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode. @@ -275,15 +275,15 @@ Please see the extension page for more details. ## Remote debugging -You can use this debugger as a remote debugger. For example, it will help the following situations: +You can use this debugger as a remote debugger. For example, it will help in the following situations: -* Your application does not run on TTY and it is hard to use `binding.pry` or `binding.irb`. - * Your application is running on Docker container and there is no TTY. +* Your application does not run on TTY, and it is hard to use `binding.pry` or `binding.irb`. + * Your application is running on a Docker container, and there is no TTY. * Your application is running as a daemon. * Your application uses pipe for STDIN or STDOUT. * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on). -You can run your application as a remote debuggee and the remote debugger console can attach to the debuggee anytime. +You can run your application as a remote debugged, and the remote debugger console can attach to the debuggee anytime. ### Invoke as a remote debuggee @@ -324,11 +324,11 @@ $ rdbg -A (rdbg:remote) ``` -If there is no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connect to it. If there are more files, you need to specify the file. +If there is no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. -When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program and so on) like local debug console. When an debuggee program exits, the remote console will also terminate. +When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate. -NOTE: If you use `quit` command, only remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. +NOTE: If you use `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. @@ -372,7 +372,7 @@ Also `open` command allows opening the debug port. ([vscode-rdbg v0.0.9](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) or later is required) -If you don't run a debuggee Ruby process on VSCode, you can attach with VSCode later with the following steps. +If you don't run a debuggee Ruby process on VSCode, you can attach to VSCode later with the following steps. `rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command). @@ -425,7 +425,7 @@ If your application is running on a SSH remote host, please try: ``` -and try to use proposed commands. +and try to use the proposed commands. Note that you can attach with `rdbg --attach` and continue REPL debugging. @@ -443,7 +443,7 @@ DEBUGGER: With Chrome browser, type the following URL in the address-bar: DEBUGGER: wait for debugger connection... ``` -Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address-bar on Chrome browser, and you can continue the debugging with chrome browser. +Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address bar on Chrome browser, and you can continue the debugging with chrome browser. Also `open chrome` command works like `open vscode`. @@ -456,7 +456,7 @@ When the debug session is started, initial scripts are loaded so you can put you ### Configuration list -You can configure debugger's behavior with environment variables and `config` command. Each configuration has environment variable and the name which can be specified by `config` command. +You can configure the debugger's behavior with environment variables and `config` command. Each configuration has an environment variable and a name which can be specified by `config` command. ``` # configuration example @@ -515,7 +515,7 @@ There are other environment variables: * `NO_COLOR`: If the value is set, set `RUBY_DEBUG_NO_COLOR` ([NO_COLOR: disabling ANSI color output in various Unix commands](https://no-color.org/)). * `RUBY_DEBUG_ENABLE`: If the value is `0`, do not enable debug.gem feature. -* `RUBY_DEBUG_ADDED_RUBYOPT`: Remove this value from `RUBYOPT` at first. This feature helps loading debug.gem with `RUBYOPT='-r debug/...'` and you don't want to derive it to child processes. In this case you can set `RUBY_DEBUG_ADDED_RUBYOPT='-r debug/...'` (same value) and this string will be deleted from `RUBYOPT` at first. +* `RUBY_DEBUG_ADDED_RUBYOPT`: Remove this value from `RUBYOPT` at first. This feature helps loading debug.gem with `RUBYOPT='-r debug/...'`, and you don't want to derive it to child processes. In this case, you can set `RUBY_DEBUG_ADDED_RUBYOPT='-r debug/...'` (same value), and this string will be deleted from `RUBYOPT` at first. * `RUBY_DEBUG_EDITOR` or `EDITOR`: An editor used by `edit` debug command. * `RUBY_DEBUG_BB`: Define `Kernel#bb` method which is alias of `Kernel#debugger`. @@ -527,7 +527,7 @@ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains * You can specify the initial script with `rdbg -x initial_script` (like gdb's `-x` option). Initial scripts are useful to write your favorite configurations. -For example, you can set break points with `break file:123` in `~/.rdbgrc`. +For example, you can set breakpoints with `break file:123` in `~/.rdbgrc`. If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing. @@ -537,16 +537,16 @@ On the debug console, you can use the following debug commands. There are additional features: -* `` without debug command is almost same as `pp `. - * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression and the result will be printed with `pp` method. So that the input `foo.bar` is same as `pp foo.bar`. - * If `` is recognized as a debug command, of course it is not evaluated as a Ruby expression, but is executed as debug command. For example, you can not evaluate such single letter local variables `i`, `b`, `n`, `c` because they are single letter debug commands. Use `p i` instead. - * So the author (Koichi Sasada) recommends to use `p`, `pp` or `eval` command to evaluate the Ruby expression everytime. +* `` without debug command is almost the same as `pp `. + * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. So that the input `foo.bar` is the same as `pp foo.bar`. + * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. + * So the author (Koichi Sasada) recommends using `p`, `pp` or `eval` command to evaluate the Ruby expression every time. * `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands. * `Ctrl-D` is equal to `quit` command. * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing) You can use the following debug commands. Each command should be written in 1 line. -The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid. +The `[...]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. The `<...>` notation means the argument. ### Control flow @@ -835,9 +835,9 @@ DEBUGGER__.start(no_color: true, # disable colorize ### `binding.break` method -`binding.break` (or `binding.b`) set breakpoints at written line. It also has several keywords. +`binding.break` (or `binding.b`) set breakpoints at the written line. It also has several keywords. -If `do: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command and continue the program. +If `do: 'command'` is specified, the debugger suspends the program, runs the `command` as a debug command, and continues the program. It is useful if you only want to call a debug command and don't want to stop there. ``` @@ -847,9 +847,9 @@ def initialize end ``` -On this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. +In this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. -If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend. +If `pre: 'command'` is specified, the debugger suspends the program and runs the `command` as a debug command, and keeps suspended. It is useful if you have operations before suspend. ``` @@ -859,7 +859,7 @@ def foo end ``` -On this case, you can see the result of `bar()` every time you stop there. +In this case, you can see the result of `bar()` every time you stop there. ## rdbg command help From baf98e42a3fc828207cb491c0720e7d12bfe6e4e Mon Sep 17 00:00:00 2001 From: Mostafa Ahangarha Date: Thu, 7 Dec 2023 19:02:07 +0330 Subject: [PATCH 175/263] Further improvement --- README.md | 28 ++++++++-------- misc/README.md.erb | 80 +++++++++++++++++++++++----------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 38b03a704..db6b7bdf1 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ DEBUGGER: Session start (pid: 7656) #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line) ``` -You can see that two breakpoints are registered. Let's continue the program by `continue` command. +You can see that two breakpoints are registered. Let's continue the program by using the `continue` command. ```shell (rdbg) continue @@ -200,8 +200,8 @@ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) ``` You can see that we can stop at line 3. -Let's see the local variables with `info` command, and continue. -You can also confirm that the program will suspend at line 5 and you can use `info` command again. +Let's see the local variables with the `info` command, and continue. +You can also confirm that the program will suspend at line 5 and you can use the `info` command again. ```shell (rdbg) info @@ -245,7 +245,7 @@ It will help if you want to know what the program is doing. If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. * Without `-c` option, `rdbg ` means that `` is Ruby script and invoke it like `ruby ` with the debugger. -* With `-c` option, `rdbg -c ` means that `` is command in `PATH` and simply invoke it with the debugger. +* With `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. Examples: * `rdbg -c -- rails server` @@ -263,12 +263,12 @@ Like other languages, you can use this debugger on the VSCode. 1. Install [VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) 2. Open `.rb` file (e.g. `target.rb`) -3. Register breakpoints with "Toggle breakpoint" in Run menu (or type F9 key) +3. Register breakpoints with "Toggle breakpoint" in the Run menu (or type F9 key) 4. Choose "Start debugging" in "Run" menu (or type F5 key) 5. You will see a dialog "Debug command line" and you can choose your favorite command line you want to run. 6. Chosen command line is invoked with `rdbg -c`, and VSCode shows the details at breakpoints. -Please refer [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode. +Please refer to [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode. You can configure the extension in `.vscode/launch.json`. Please see the extension page for more details. @@ -283,7 +283,7 @@ You can use this debugger as a remote debugger. For example, it will help in the * Your application uses pipe for STDIN or STDOUT. * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on). -You can run your application as a remote debugged, and the remote debugger console can attach to the debuggee anytime. +You can run your application as a remote debuggee, and the remote debugger console can attach to the debuggee anytime. ### Invoke as a remote debuggee @@ -305,7 +305,7 @@ DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock DEBUGGER: wait for debugger connection... ``` -By default, `rdbg --open` uses UNIX domain socket and generates path name automatically (`/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773` in this case). +By default, `rdbg --open` uses UNIX domain socket and generates the path name automatically (`/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773` in this case). You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short). @@ -324,11 +324,11 @@ $ rdbg -A (rdbg:remote) ``` -If there is no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. +If there are no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate. -NOTE: If you use `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. +NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. @@ -343,11 +343,11 @@ Note that all messages communicated between the debugger and the debuggee are *N #### `require 'debug/open'` in a program -If you can modify the program, you can open debugging port by adding `require 'debug/open'` line in the program. +If you can modify the program, you can open the debugging port by adding `require 'debug/open'` line in the program. If you don't want to stop the program at the beginning, you can also use `require 'debug/open_nonstop'`. Using `debug/open_nonstop` is useful if you want to open a backdoor to the application. -However, it is also danger because it can become another vulnerability. +However, it is also dangerous because it can become another vulnerability. Please use it carefully. By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. @@ -372,7 +372,7 @@ Also `open` command allows opening the debug port. ([vscode-rdbg v0.0.9](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) or later is required) -If you don't run a debuggee Ruby process on VSCode, you can attach to VSCode later with the following steps. +If you don't run a debuggee Ruby process on VSCode, you can attach it to VSCode later with the following steps. `rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command). @@ -816,7 +816,7 @@ Emacs support available. #### Start by method -After loading `debug/session`, you can start debug session with the following methods. They are convenient if you want to specify debug configurations in your program. +After loading `debug/session`, you can start a debug session with the following methods. They are convenient if you want to specify debug configurations in your program. * `DEBUGGER__.start(**kw)`: start debug session with local console. * `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket) diff --git a/misc/README.md.erb b/misc/README.md.erb index ff800fabf..d591a2f2b 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -4,7 +4,7 @@ This library provides debugging functionality to Ruby (MRI) 2.7 and later. -This debug.rb is replacement of traditional lib/debug.rb standard library which is implemented by `set_trace_func`. +This debug.rb is the replacement of traditional lib/debug.rb standard library, which is implemented by `set_trace_func`. New debug.rb has several advantages: * Fast: No performance penalty on non-stepping mode and non-breakpoints. @@ -18,7 +18,7 @@ New debug.rb has several advantages: Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | -* Extensible: application can introduce debugging support with several ways: +* Extensible: application can introduce debugging support in several ways: * By `rdbg` command * By loading libraries with `-r` command line option * By calling Ruby's method explicitly @@ -55,7 +55,7 @@ To use a debugger, roughly you will do the following steps: 4. Use debug commands. * [Evaluate Ruby expressions](#evaluate) (e.g. `p lvar` to see the local variable `lvar`). * [Query the program status](#information) (e.g. `info` to see information about the current frame). - * [Control program flow](#control-flow) (e.g. move to the another line with `step`, to the next line with `next`). + * [Control program flow](#control-flow) (e.g. move to another line with `step`, to the next line with `next`). * [Set another breakpoint](#breakpoint) (e.g. `catch Exception` to set a breakpoint that'll be triggered when `Exception` is raised). * [Activate tracing in your program](#trace) (e.g. `trace call` to trace method calls). * [Change the configuration](#configuration-1) (e.g. `config set no_color true` to disable coloring). @@ -180,7 +180,7 @@ DEBUGGER: Session start (pid: 7656) #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line) ``` -You can see that two breakpoints are registered. Let's continue the program by `continue` command. +You can see that two breakpoints are registered. Let's continue the program by using the `continue` command. ```shell (rdbg) continue @@ -200,8 +200,8 @@ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) ``` You can see that we can stop at line 3. -Let's see the local variables with `info` command, and continue. -You can also confirm that the program will suspend at line 5 and you can use `info` command again. +Let's see the local variables with the `info` command, and continue. +You can also confirm that the program will suspend at line 5 and you can use the `info` command again. ```shell (rdbg) info @@ -238,14 +238,14 @@ d => 4 ``` By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console. -It will help that if you want to know what the program is doing. +It will help if you want to know what the program is doing. ### Use `rdbg` with commands written in Ruby -If you want to run a command written in Ruby like like `rake`, `rails`, `bundle`, `rspec` and so on, you can use `rdbg -c` option. +If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. * Without `-c` option, `rdbg ` means that `` is Ruby script and invoke it like `ruby ` with the debugger. -* With `-c` option, `rdbg -c ` means that `` is command in `PATH` and simply invoke it with the debugger. +* With `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. Examples: * `rdbg -c -- rails server` @@ -263,27 +263,27 @@ Like other languages, you can use this debugger on the VSCode. 1. Install [VSCode rdbg Ruby Debugger - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) 2. Open `.rb` file (e.g. `target.rb`) -3. Register breakpoints with "Toggle breakpoint" in Run menu (or type F9 key) +3. Register breakpoints with "Toggle breakpoint" in the Run menu (or type F9 key) 4. Choose "Start debugging" in "Run" menu (or type F5 key) -5. You will see a dialog "Debug command line" and you can choose your favorite command line your want to run. -6. Chosen command line is invoked with `rdbg -c` and VSCode shows the details at breakpoints. +5. You will see a dialog "Debug command line" and you can choose your favorite command line you want to run. +6. Chosen command line is invoked with `rdbg -c`, and VSCode shows the details at breakpoints. -Please refer [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode. +Please refer to [Debugging in Visual Studio Code](https://code.visualstudio.com/docs/editor/debugging) for operations on VSCode. You can configure the extension in `.vscode/launch.json`. Please see the extension page for more details. ## Remote debugging -You can use this debugger as a remote debugger. For example, it will help the following situations: +You can use this debugger as a remote debugger. For example, it will help in the following situations: -* Your application does not run on TTY and it is hard to use `binding.pry` or `binding.irb`. - * Your application is running on Docker container and there is no TTY. +* Your application does not run on TTY, and it is hard to use `binding.pry` or `binding.irb`. + * Your application is running on a Docker container, and there is no TTY. * Your application is running as a daemon. * Your application uses pipe for STDIN or STDOUT. * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on). -You can run your application as a remote debuggee and the remote debugger console can attach to the debuggee anytime. +You can run your application as a remote debuggee, and the remote debugger console can attach to the debuggee anytime. ### Invoke as a remote debuggee @@ -305,7 +305,7 @@ DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock DEBUGGER: wait for debugger connection... ``` -By default, `rdbg --open` uses UNIX domain socket and generates path name automatically (`/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773` in this case). +By default, `rdbg --open` uses UNIX domain socket and generates the path name automatically (`/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773` in this case). You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short). @@ -324,11 +324,11 @@ $ rdbg -A (rdbg:remote) ``` -If there is no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connect to it. If there are more files, you need to specify the file. +If there are no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. -When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program and so on) like local debug console. When an debuggee program exits, the remote console will also terminate. +When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate. -NOTE: If you use `quit` command, only remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. +NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. @@ -343,11 +343,11 @@ Note that all messages communicated between the debugger and the debuggee are *N #### `require 'debug/open'` in a program -If you can modify the program, you can open debugging port by adding `require 'debug/open'` line in the program. +If you can modify the program, you can open the debugging port by adding `require 'debug/open'` line in the program. If you don't want to stop the program at the beginning, you can also use `require 'debug/open_nonstop'`. Using `debug/open_nonstop` is useful if you want to open a backdoor to the application. -However, it is also danger because it can become another vulnerability. +However, it is also dangerous because it can become another vulnerability. Please use it carefully. By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. @@ -372,7 +372,7 @@ Also `open` command allows opening the debug port. ([vscode-rdbg v0.0.9](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) or later is required) -If you don't run a debuggee Ruby process on VSCode, you can attach with VSCode later with the following steps. +If you don't run a debuggee Ruby process on VSCode, you can attach it to VSCode later with the following steps. `rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command). @@ -425,7 +425,7 @@ If your application is running on a SSH remote host, please try: ``` -and try to use proposed commands. +and try to use the proposed commands. Note that you can attach with `rdbg --attach` and continue REPL debugging. @@ -443,7 +443,7 @@ DEBUGGER: With Chrome browser, type the following URL in the address-bar: DEBUGGER: wait for debugger connection... ``` -Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address-bar on Chrome browser, and you can continue the debugging with chrome browser. +Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address bar on Chrome browser, and you can continue the debugging with chrome browser. Also `open chrome` command works like `open vscode`. @@ -456,7 +456,7 @@ When the debug session is started, initial scripts are loaded so you can put you ### Configuration list -You can configure debugger's behavior with environment variables and `config` command. Each configuration has environment variable and the name which can be specified by `config` command. +You can configure the debugger's behavior with environment variables and `config` command. Each configuration has an environment variable and a name which can be specified by `config` command. ``` # configuration example @@ -473,7 +473,7 @@ There are other environment variables: * `NO_COLOR`: If the value is set, set `RUBY_DEBUG_NO_COLOR` ([NO_COLOR: disabling ANSI color output in various Unix commands](https://no-color.org/)). * `RUBY_DEBUG_ENABLE`: If the value is `0`, do not enable debug.gem feature. -* `RUBY_DEBUG_ADDED_RUBYOPT`: Remove this value from `RUBYOPT` at first. This feature helps loading debug.gem with `RUBYOPT='-r debug/...'` and you don't want to derive it to child processes. In this case you can set `RUBY_DEBUG_ADDED_RUBYOPT='-r debug/...'` (same value) and this string will be deleted from `RUBYOPT` at first. +* `RUBY_DEBUG_ADDED_RUBYOPT`: Remove this value from `RUBYOPT` at first. This feature helps loading debug.gem with `RUBYOPT='-r debug/...'`, and you don't want to derive it to child processes. In this case, you can set `RUBY_DEBUG_ADDED_RUBYOPT='-r debug/...'` (same value), and this string will be deleted from `RUBYOPT` at first. * `RUBY_DEBUG_EDITOR` or `EDITOR`: An editor used by `edit` debug command. * `RUBY_DEBUG_BB`: Define `Kernel#bb` method which is alias of `Kernel#debugger`. @@ -485,7 +485,7 @@ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains * You can specify the initial script with `rdbg -x initial_script` (like gdb's `-x` option). Initial scripts are useful to write your favorite configurations. -For example, you can set break points with `break file:123` in `~/.rdbgrc`. +For example, you can set breakpoints with `break file:123` in `~/.rdbgrc`. If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing. @@ -495,16 +495,16 @@ On the debug console, you can use the following debug commands. There are additional features: -* `` without debug command is almost same as `pp `. - * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression and the result will be printed with `pp` method. So that the input `foo.bar` is same as `pp foo.bar`. - * If `` is recognized as a debug command, of course it is not evaluated as a Ruby expression, but is executed as debug command. For example, you can not evaluate such single letter local variables `i`, `b`, `n`, `c` because they are single letter debug commands. Use `p i` instead. - * So the author (Koichi Sasada) recommends to use `p`, `pp` or `eval` command to evaluate the Ruby expression everytime. +* `` without debug command is almost the same as `pp `. + * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. So that the input `foo.bar` is the same as `pp foo.bar`. + * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. + * So the author (Koichi Sasada) recommends using `p`, `pp` or `eval` command to evaluate the Ruby expression every time. * `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands. * `Ctrl-D` is equal to `quit` command. * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing) You can use the following debug commands. Each command should be written in 1 line. -The `[...]` notation means this part can be eliminate. For example, `s[tep]` means `s` or `step` are valid command. `ste` is not valid. +The `[...]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. The `<...>` notation means the argument. <%= DEBUGGER__.help %> @@ -541,7 +541,7 @@ Emacs support available. #### Start by method -After loading `debug/session`, you can start debug session with the following methods. They are convenient if you want to specify debug configurations in your program. +After loading `debug/session`, you can start a debug session with the following methods. They are convenient if you want to specify debug configurations in your program. * `DEBUGGER__.start(**kw)`: start debug session with local console. * `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket) @@ -560,9 +560,9 @@ DEBUGGER__.start(no_color: true, # disable colorize ### `binding.break` method -`binding.break` (or `binding.b`) set breakpoints at written line. It also has several keywords. +`binding.break` (or `binding.b`) set breakpoints at the written line. It also has several keywords. -If `do: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command and continue the program. +If `do: 'command'` is specified, the debugger suspends the program, runs the `command` as a debug command, and continues the program. It is useful if you only want to call a debug command and don't want to stop there. ``` @@ -572,9 +572,9 @@ def initialize end ``` -On this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. +In this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. -If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend. +If `pre: 'command'` is specified, the debugger suspends the program and runs the `command` as a debug command, and keeps suspended. It is useful if you have operations before suspend. ``` @@ -584,7 +584,7 @@ def foo end ``` -On this case, you can see the result of `bar()` every time you stop there. +In this case, you can see the result of `bar()` every time you stop there. ## rdbg command help From 17345bf02d3eaa62d294fb9835442967d0b7084a Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 4 Jun 2023 13:17:22 +0900 Subject: [PATCH 176/263] Don't let `@q_cmd.pop` enter the fiber scheduler. --- lib/debug/thread_client.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 6f9da4af1..332100ba7 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -862,8 +862,19 @@ def make_breakpoint args class SuspendReplay < Exception end + if ::Fiber.respond_to?(:blocking) + private def fiber_blocking + ::Fiber.blocking{yield} + end + else + private def fiber_blocking + yield + end + end + + def wait_next_action - wait_next_action_ + fiber_blocking{wait_next_action_} rescue SuspendReplay replay_suspend end From 671676276697f873b0ccf47d69038d8258dd57b3 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 4 Jun 2023 13:55:42 +0900 Subject: [PATCH 177/263] Increase timeout to 30 seconds. --- test/support/cdp_utils.rb | 2 +- test/support/dap_utils.rb | 2 +- test/support/protocol_test_case.rb | 2 +- test/support/test_case.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/support/cdp_utils.rb b/test/support/cdp_utils.rb index 144904eab..a6c927c64 100644 --- a/test/support/cdp_utils.rb +++ b/test/support/cdp_utils.rb @@ -63,7 +63,7 @@ def connect_to_cdp_server MSG end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i HOST = '127.0.0.1' def run_cdp_scenario program, &msgs diff --git a/test/support/dap_utils.rb b/test/support/dap_utils.rb index 634f70792..69c305c2f 100644 --- a/test/support/dap_utils.rb +++ b/test/support/dap_utils.rb @@ -96,7 +96,7 @@ def connect_to_dap_server test_info sock end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i def run_dap_scenario program, &msgs begin diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 902955c0d..71cf11a05 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -644,7 +644,7 @@ def send **kw end end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i def assert_dap_response expected_def, result_res return unless defined? DAP_HASH diff --git a/test/support/test_case.rb b/test/support/test_case.rb index fae5b9f58..0704a4bb2 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -96,7 +96,7 @@ def debug_print msg RUBY = ENV['RUBY'] || RbConfig.ruby RDBG_EXECUTABLE = "#{RUBY} #{__dir__}/../../exe/rdbg" - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i def get_target_ui ENV['RUBY_DEBUG_TEST_UI'] From bfe9568a8eb85cc004d235c50382d5ad0d472b23 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 4 Jun 2023 15:48:45 +0900 Subject: [PATCH 178/263] Use actual per-thread variable. --- lib/debug/thread_client.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 332100ba7..fbb1dd281 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -5,6 +5,10 @@ require_relative 'color' +class ::Thread + attr_accessor :debug_thread_client +end + module DEBUGGER__ M_INSTANCE_VARIABLES = method(:instance_variables).unbind M_INSTANCE_VARIABLE_GET = method(:instance_variable_get).unbind @@ -48,12 +52,7 @@ def safe_global_variables class ThreadClient def self.current - if thc = Thread.current[:DEBUGGER__ThreadClient] - thc - else - thc = SESSION.get_thread_client - Thread.current[:DEBUGGER__ThreadClient] = thc - end + Thread.current.debug_thread_client ||= SESSION.get_thread_client end include Color From 0b32043433e4d6cae96f0c7e56caabf18d4d15cd Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 21 Oct 2023 14:19:49 +1300 Subject: [PATCH 179/263] Support Ruby 3.1+. --- lib/debug/thread_client.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index fbb1dd281..332e50cb8 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -865,12 +865,15 @@ class SuspendReplay < Exception private def fiber_blocking ::Fiber.blocking{yield} end + elsif ::Fiber.method_defined?(:blocking?) + private def fiber_blocking + ::Fiber.new(blocking: true){yield}.resume + end else private def fiber_blocking yield end end - def wait_next_action fiber_blocking{wait_next_action_} From 9c3b8c4ffbb04a5080b8788f10b698bc4406f1bc Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 8 Dec 2023 23:11:18 +0900 Subject: [PATCH 180/263] Revert "Increase timeout to 30 seconds." This reverts commit 671676276697f873b0ccf47d69038d8258dd57b3. https://github.com/ruby/debug/pull/987#discussion_r1420909275 --- test/support/cdp_utils.rb | 2 +- test/support/dap_utils.rb | 2 +- test/support/protocol_test_case.rb | 2 +- test/support/test_case.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/support/cdp_utils.rb b/test/support/cdp_utils.rb index a6c927c64..144904eab 100644 --- a/test/support/cdp_utils.rb +++ b/test/support/cdp_utils.rb @@ -63,7 +63,7 @@ def connect_to_cdp_server MSG end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i HOST = '127.0.0.1' def run_cdp_scenario program, &msgs diff --git a/test/support/dap_utils.rb b/test/support/dap_utils.rb index 69c305c2f..634f70792 100644 --- a/test/support/dap_utils.rb +++ b/test/support/dap_utils.rb @@ -96,7 +96,7 @@ def connect_to_dap_server test_info sock end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i def run_dap_scenario program, &msgs begin diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 71cf11a05..902955c0d 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -644,7 +644,7 @@ def send **kw end end - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i def assert_dap_response expected_def, result_res return unless defined? DAP_HASH diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 0704a4bb2..fae5b9f58 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -96,7 +96,7 @@ def debug_print msg RUBY = ENV['RUBY'] || RbConfig.ruby RDBG_EXECUTABLE = "#{RUBY} #{__dir__}/../../exe/rdbg" - TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 30).to_i + TIMEOUT_SEC = (ENV['RUBY_DEBUG_TIMEOUT_SEC'] || 10).to_i def get_target_ui ENV['RUBY_DEBUG_TEST_UI'] From 3d4458499a07bf8dee1f6a8e979eefba034fc16c Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 8 Dec 2023 23:58:09 +0900 Subject: [PATCH 181/263] fix indentation --- test/console/backtrace_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index 3fcdf81ee..3f926aebb 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -189,7 +189,7 @@ def test_backtrace_prints_nested_block_label_correctly end end - class ThreadLockingTraceTest < ConsoleTestCase + class ThreadLockingTraceTest < ConsoleTestCase def program <<~RUBY 1| th0 = Thread.new{sleep} From 04c22c5760e3475446c92955023d636694a4175f Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 9 Dec 2023 00:16:41 +0900 Subject: [PATCH 182/263] Do not make a Fiber for commands because context was changed on suspended threads. --- lib/debug/thread_client.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 332e50cb8..753898560 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -865,10 +865,6 @@ class SuspendReplay < Exception private def fiber_blocking ::Fiber.blocking{yield} end - elsif ::Fiber.method_defined?(:blocking?) - private def fiber_blocking - ::Fiber.new(blocking: true){yield}.resume - end else private def fiber_blocking yield From acd5fc51c2b00ed18e9a7bb316380e8a69cd0ecf Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sat, 9 Dec 2023 11:35:17 +0900 Subject: [PATCH 183/263] support Ruby 3.3 by skipping `bundled_gems.rb` --- lib/debug/session.rb | 1 + test/console/rdbg_option_test.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3d973c3d2..f76f9dc6d 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2190,6 +2190,7 @@ def self.require_location case loc.absolute_path when dir_prefix when %r{rubygems/core_ext/kernel_require\.rb} + when %r{bundled_gems\.rb} else return loc if loc.absolute_path end diff --git a/test/console/rdbg_option_test.rb b/test/console/rdbg_option_test.rb index 615b07ef3..c173c33bd 100644 --- a/test/console/rdbg_option_test.rb +++ b/test/console/rdbg_option_test.rb @@ -72,7 +72,7 @@ def program def test_debugger_stops_immediately run_rdbg(program, options: "--stop-at-load") do # stops at the earliest possible location - assert_line_text(/\[C\] Kernel#require/) + assert_line_text(/\[C\] Kernel[#\.]require/) type "c" type "a + 'bar'" assert_line_text(/foobar/) From c855148f1cefa7f741f0974b1dc4d5f5d989e201 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Sun, 10 Dec 2023 06:03:01 +0900 Subject: [PATCH 184/263] check 3.2 on protocol.yml --- .github/workflows/protocol.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index b29d09074..7878ff872 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "head", "debug"] + ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] steps: - uses: actions/checkout@v4 From 65519e41cbd73b2e2b6c1232cf59ee5708ca7e43 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Mon, 11 Dec 2023 03:23:28 +0900 Subject: [PATCH 185/263] v1.9.0 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index ae8afe5f4..02ffc5e60 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.8.0" + VERSION = "1.9.0" end From d4feeae32b69b4f88c94fecfc7a283b475eec4de Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Mon, 11 Dec 2023 05:57:28 +0900 Subject: [PATCH 186/263] fix condition of USE_TMP_HOME Use tmp home if home can be changed. fix https://github.com/ruby/actions/actions/runs/7164065566/job/19503611173 ``` > /home/runner/work/actions/actions/ruby-3.3.0-rc1/lib/irb/history.rb:62:in `initialize': Permission denied @ rb_sysopen - /home/runner/.irb_history (Errno::EACCES) ... ``` --- test/support/console_test_case.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index efdc1bafe..88d2764f7 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -21,7 +21,7 @@ class ConsoleTestCase < TestCase PTY.spawn({ "HOME" => pwd }, ruby, '-e', 'puts ENV["HOME"]') do |r,| home_cannot_change = r.gets.chomp != pwd end - home_cannot_change + !home_cannot_change end class << self From 52694a9e05aea1ae5bcd9c13591bb3f06724bde6 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Mon, 11 Dec 2023 08:52:01 +0900 Subject: [PATCH 187/263] add verbose mode for `debug_code` show backlog if verbose is true. --- test/support/console_test_case.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index 88d2764f7..f7e62fb4b 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -85,7 +85,7 @@ def create_message fail_msg, test_info MSG end - def debug_code(program, remote: true, &test_steps) + def debug_code(program, remote: true, verbose: false, &test_steps) Timeout.timeout(60) do prepare_test_environment(program, test_steps) do if remote && !NO_REMOTE && MULTITHREADED_TEST @@ -109,17 +109,17 @@ def debug_code(program, remote: true, &test_steps) th.each {|t| t.join} end elsif remote && !NO_REMOTE - debug_code_on_local unless remote == :remote_only + debug_code_on_local verbose: verbose unless remote == :remote_only debug_code_on_unix_domain_socket debug_code_on_tcpip else - debug_code_on_local unless remote == :remote_only + debug_code_on_local verbose: verbose unless remote == :remote_only end end end end - def run_test_scenario cmd, test_info + def run_test_scenario cmd, test_info, verbose: false PTY.spawn({ "HOME" => pty_home_dir }, cmd) do |read, write, pid| test_info.backlog = [] test_info.last_backlog = [] @@ -206,6 +206,8 @@ def run_test_scenario cmd, test_info kill_safely pid, force: is_assertion_failure end end + ensure + pp backlog: test_info.backlog if verbose end def assert_program_finish test_info, pid, name @@ -249,10 +251,10 @@ def manual_debug_code(program) kill_remote_debuggee remote_info end - private def debug_code_on_local + private def debug_code_on_local verbose: false test_info = TestInfo.new(dup_scenario, 'LOCAL', /\(rdbg\)/) cmd = "#{RDBG_EXECUTABLE} #{temp_file_path}" - run_test_scenario cmd, test_info + run_test_scenario cmd, test_info, verbose: verbose end private def debug_code_on_unix_domain_socket From 557233a90ff623c7dd00384a08471e5a5514f688 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Mon, 11 Dec 2023 09:43:24 +0900 Subject: [PATCH 188/263] fix bt on nested break points `di_body()` doesn't filter C locations. --- ext/debug/debug.c | 16 ++++++++++++---- test/console/nested_break_test.rb | 27 ++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index d7bb3e2ab..ad8431cef 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -62,15 +62,23 @@ di_body(const rb_debug_inspector_t *dc, void *ptr) long i; for (i=1; i/) # TODO: can be changed type 'c' assert_line_text(/143/) From 9de0ff46faeea73aed27bb090ee052db8fb74c14 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 22 Dec 2023 12:09:49 +0900 Subject: [PATCH 189/263] v1.9.1 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 02ffc5e60..6ccf565c8 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.9.0" + VERSION = "1.9.1" end From 6a9c75fd0c7b21b20d0cb62882afb913ee9b5352 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Tue, 2 Jan 2024 13:30:18 +0000 Subject: [PATCH 190/263] Add Ruby 3.3 to CI matrix --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby-macos.yaml | 2 +- .github/workflows/ruby.yml | 2 +- .github/workflows/test_test.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 7878ff872..755557039 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] + ruby-version: ["2.7", "3.0", "3.1", "3.2", "3.3", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index e13e52b6c..4b04e8647 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['3.2', 'head'] + ruby-version: ["3.2", "3.3", "head"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 4662ef6a7..dd76ced54 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "3.2", "head", "debug"] + ruby-version: ["2.7", "3.0", "3.1", "3.2", "3.3", "head", "debug"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index e65ded2bf..3123697fe 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - ruby-version: ['3.0', '3.1', '3.2', 'head', 'debug'] + ruby-version: ["3.0", "3.1", "3.2", "3.3", "head", "debug"] steps: - uses: actions/checkout@v4 From ab937ac49a4643f9302856c2da487ca113c16bd5 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Sun, 31 Dec 2023 13:57:51 +0000 Subject: [PATCH 191/263] Correct the irb command's description --- README.md | 2 +- lib/debug/session.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db6b7bdf1..040bba498 100644 --- a/README.md +++ b/README.md @@ -713,7 +713,7 @@ The `<...>` notation means the argument. * `eval ` * Evaluate `` on the current frame. * `irb` - * Invoke `irb` on the current frame. + * Activate and switch to `irb:rdbg` console ### Trace diff --git a/lib/debug/session.rb b/lib/debug/session.rb index f76f9dc6d..c5b410182 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -938,7 +938,7 @@ def register_default_command end # * `irb` - # * Invoke `irb` on the current frame. + # * Activate and switch to `irb:rdbg` console register_command 'irb' do |arg| if @ui.remote? @ui.puts "\nIRB is not supported on the remote console." From 19b91b14ce814a0eb615abb8d2bef0594c61c5c8 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 12 Jan 2024 14:22:14 -0800 Subject: [PATCH 192/263] Stop assuming Array#each is written in C Same as https://github.com/ruby/debug/pull/1015, but for Array#each. We're thinking of rewriting it in Ruby, and I'd like to avoid failing on test-bundled-gems in the PR. --- test/console/backtrace_test.rb | 4 ++-- test/console/break_test.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index 3f926aebb..570d66c80 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -22,7 +22,7 @@ def program 14| end 15| end 16| - 17| [1, 2, 3].each do + 17| [1, 2, 3].reverse_each do 18| Foo.new.first_call 19| end RUBY @@ -33,7 +33,7 @@ def test_backtrace_prints_c_method_frame type 'b 18' type 'c' type 'bt' - assert_line_text(/\[C\] Array#each/) + assert_line_text(/\[C\] Array#reverse_each/) type 'kill!' end end diff --git a/test/console/break_test.rb b/test/console/break_test.rb index dc06f3d1d..2b8f989ce 100644 --- a/test/console/break_test.rb +++ b/test/console/break_test.rb @@ -384,11 +384,11 @@ def test_break_only_stops_when_path_matches class BreakAtCMethod2Test < ConsoleTestCase def program <<~RUBY - 1| binding.b(do: "b Array#each") + 1| binding.b(do: "b Array#reverse_each") 2| 3| result = "" 4| - 5| [1, 2, 3].each do |i| + 5| [1, 2, 3].reverse_each do |i| 6| result += i.to_s 7| end 8| From c82c58044e3881e3c17852e398c3ef8e8aa72936 Mon Sep 17 00:00:00 2001 From: Adam Daniels Date: Thu, 28 Dec 2023 12:08:24 -0500 Subject: [PATCH 193/263] Fix prelude doc example to use curly braces Using round parens is shell execution. --- lib/debug/prelude.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/prelude.rb b/lib/debug/prelude.rb index 0f6611963..c83c63a5f 100644 --- a/lib/debug/prelude.rb +++ b/lib/debug/prelude.rb @@ -5,7 +5,7 @@ # Put the following line in your login script (e.g. ~/.bash_profile) with modified path: # -# export RUBYOPT="-r /path/to/debug/prelude $(RUBYOPT)" +# export RUBYOPT="-r /path/to/debug/prelude ${RUBYOPT}" # module Kernel def debugger(*a, up_level: 0, **kw) From 61de9d87f02fca5d46561157abdce168022a9eb5 Mon Sep 17 00:00:00 2001 From: "yuuji.yaginuma" Date: Sun, 21 Jan 2024 14:31:44 +0900 Subject: [PATCH 194/263] Add `base64` gem to the dependency Since Ruby 3.3.0, RubyGems and Bundler warn if users do require the gems that will become the bundled gems in the future version of Ruby. https://www.ruby-lang.org/en/news/2023/12/25/ruby-3-3-0-released/ `debug` uses one of those gems, `base64`. https://github.com/ruby/debug/blob/c82c58044e3881e3c17852e398c3ef8e8aa72936/lib/debug/server_cdp.rb#L5 So if a user use `debug` gem with Chrome, a user will get the warning about that. ``` $ bundle exec rdbg --open=chrome main.rb /home/y-yagi/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/debug-1.9.1/lib/debug/server_cdp.rb:5: warning: base64 was loaded from the standard library, but will no longer be part of the default gems since Ruby 3.4.0. Add base64 to your Gemfile or gemspec. Also contact author of debug-1.9.1 to add base64 into its gemspec. ``` This PR adds `base64` as the dependency to fix the warning. --- debug.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/debug.gemspec b/debug.gemspec index 2a5891f32..b0d0f7139 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -29,4 +29,5 @@ Gem::Specification.new do |spec| spec.add_dependency "irb", "~> 1.10" # for irb:debug integration spec.add_dependency "reline", ">= 0.3.8" + spec.add_dependency "base64" end From 62ea9d1b08ea5c2ed4a681088376fba5e4a85954 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 29 Jan 2024 11:35:15 +0900 Subject: [PATCH 195/263] Add launchable integration --- .github/workflows/protocol.yml | 37 ++++++++++++++++++++++++++++++- .github/workflows/ruby-macos.yaml | 37 ++++++++++++++++++++++++++++++- .github/workflows/ruby.yml | 37 ++++++++++++++++++++++++++++++- .github/workflows/test_test.yml | 37 ++++++++++++++++++++++++++++++- Gemfile | 1 + test/support/test_case.rb | 2 ++ 6 files changed, 147 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 755557039..984819287 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -6,6 +6,17 @@ on: pull_request: branches: [ master ] +env: + # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 + GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} + # The following envs are necessary in Launchable tokenless authentication. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 + LAUNCHABLE_ORGANIZATION: "ruby" + LAUNCHABLE_WORKSPACE: "debug" + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + jobs: test: @@ -18,6 +29,27 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 0 so that Launchable can receive commits information. + fetch-depth: 0 + # Launchable requires Python and Java + # https://www.launchableinc.com/docs/resources/cli-reference/ + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Set up JDK 1.8 + uses: actions/setup-java@v3 + with: + distribution: 'adopt' + java-version: '8' + # Setup Launchable + - name: Launchable - install command + run: pip install launchable + - name: Launchable - verify + run: launchable verify + - name: Launchable - record build + run: launchable record build --name ${GITHUB_PR_HEAD_SHA} + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -27,4 +59,7 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_protocol + TESTOPTS="--runner=junitxml --junitxml-output-file=protocol.xml" bundle exec rake test_protocol + - name: Launchable - record tests + run: launchable record tests --flavor test=protocol --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file protocol.xml + if: always() diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 4b04e8647..97a072686 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -6,6 +6,17 @@ on: pull_request: branches: [ master ] +env: + # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 + GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} + # The following envs are necessary in Launchable tokenless authentication. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 + LAUNCHABLE_ORGANIZATION: "ruby" + LAUNCHABLE_WORKSPACE: "debug" + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + jobs: test: @@ -18,6 +29,27 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 0 so that Launchable can receive commits information. + fetch-depth: 0 + # Launchable requires Python and Java + # https://www.launchableinc.com/docs/resources/cli-reference/ + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Set up JDK 1.8 + uses: actions/setup-java@v3 + with: + distribution: 'adopt' + java-version: '8' + # Setup Launchable + - name: Launchable - install command + run: pip install launchable + - name: Launchable - verify + run: launchable verify + - name: Launchable - record build + run: launchable record build --name ${GITHUB_PR_HEAD_SHA} + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -27,4 +59,7 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_console + TESTOPTS="--runner=junitxml --junitxml-output-file=ruby-macos.xml" bundle exec rake test_console + - name: launchable record tests + run: launchable record tests --flavor test=console --flavor os=macos-latest --flavor ruby=${{ matrix.ruby-version }} file ruby-macos.xml + if: always() diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index dd76ced54..c5052e5fd 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -6,6 +6,17 @@ on: pull_request: branches: [ master ] +env: + # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 + GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} + # The following envs are necessary in Launchable tokenless authentication. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 + LAUNCHABLE_ORGANIZATION: "ruby" + LAUNCHABLE_WORKSPACE: "debug" + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + jobs: test: @@ -18,6 +29,27 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 0 so that Launchable can receive commits information. + fetch-depth: 0 + # Launchable requires Python and Java + # https://www.launchableinc.com/docs/resources/cli-reference/ + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Set up JDK 1.8 + uses: actions/setup-java@v3 + with: + distribution: 'adopt' + java-version: '8' + # Setup Launchable + - name: Launchable - install command + run: pip install launchable + - name: Launchable - verify + run: launchable verify + - name: Launchable - record build + run: launchable record build --name ${GITHUB_PR_HEAD_SHA} + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -27,4 +59,7 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_console + TESTOPTS="--runner=junitxml --junitxml-output-file=ruby.xml" bundle exec rake test_console + - name: launchable record tests + run: launchable record tests --flavor test=console --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file ruby.xml + if: always() diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 3123697fe..0a45b7c34 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -6,6 +6,17 @@ on: pull_request: branches: [ master ] +env: + # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 + GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} + # The following envs are necessary in Launchable tokenless authentication. + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 + LAUNCHABLE_ORGANIZATION: "ruby" + LAUNCHABLE_WORKSPACE: "debug" + # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + jobs: test: @@ -18,6 +29,27 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 0 so that Launchable can receive commits information. + fetch-depth: 0 + # Launchable requires Python and Java + # https://www.launchableinc.com/docs/resources/cli-reference/ + - uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: Set up JDK 1.8 + uses: actions/setup-java@v3 + with: + distribution: 'adopt' + java-version: '8' + # Setup Launchable + - name: Launchable - install command + run: pip install launchable + - name: Launchable - verify + run: launchable verify + - name: Launchable - record build + run: launchable record build --name ${GITHUB_PR_HEAD_SHA} + - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -27,4 +59,7 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_test + TESTOPTS="--runner=junitxml --junitxml-output-file=test_test.xml" bundle exec rake test_test + - name: launchable record tests + run: launchable record tests --flavor test=test-framework --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file test_test.xml + if: always() diff --git a/Gemfile b/Gemfile index c59ccbe1a..50630d1e8 100644 --- a/Gemfile +++ b/Gemfile @@ -7,3 +7,4 @@ gem "rake-compiler" gem "test-unit", "~> 3.0" gem "test-unit-rr" gem "json-schema" +gem "test-unit-runner-junitxml" diff --git a/test/support/test_case.rb b/test/support/test_case.rb index fae5b9f58..5725e8df2 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -7,6 +7,8 @@ require 'timeout' require 'json' require 'rbconfig' +# "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. +require "test/unit/runner/junitxml" require_relative '../../lib/debug/client' require_relative 'assertions' From 8d205e4296b9e0abbd571b3a5796f478e9bb5093 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 9 Feb 2024 15:02:34 +0900 Subject: [PATCH 196/263] require "test/unit/runner/junitxml" if launchable env is configured --- test/support/test_case.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5725e8df2..766dc5055 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -7,12 +7,15 @@ require 'timeout' require 'json' require 'rbconfig' -# "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. -require "test/unit/runner/junitxml" require_relative '../../lib/debug/client' require_relative 'assertions' +if ENV['LAUNCHABLE_ORGANIZATION'] && ENV['LAUNCHABLE_WORKSPACE'] + # "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. + require "test/unit/runner/junitxml" +end + module DEBUGGER__ class TestCase < Test::Unit::TestCase TestInfo = Struct.new(:queue, :mode, :prompt_pattern, :remote_info, From 0158b3d6b4d80138609de97ff6cf63830f7612b3 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 9 Feb 2024 15:11:10 +0900 Subject: [PATCH 197/263] Add comment --- test/support/test_case.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 766dc5055..d20f91622 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -11,6 +11,8 @@ require_relative 'assertions' +# Load this library only in the debug CI to prevent LoadError +# when these tests are executed in ruby/ruby. if ENV['LAUNCHABLE_ORGANIZATION'] && ENV['LAUNCHABLE_WORKSPACE'] # "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. require "test/unit/runner/junitxml" From fa52fcde8bf255c515e40b1910287b3dd54b6b19 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Fri, 9 Feb 2024 15:53:19 +0900 Subject: [PATCH 198/263] Use `github.sha` when running tests on the master branch --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby-macos.yaml | 2 +- .github/workflows/ruby.yml | 2 +- .github/workflows/test_test.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 984819287..cfe560403 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} jobs: test: diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 97a072686..5d505fae7 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} jobs: test: diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index c5052e5fd..c3f6e7e2d 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} jobs: test: diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 0a45b7c34..c3955fc20 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} jobs: test: From cfa0da200cf48670fa119000e25eeb59c002e34b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 19 Feb 2024 17:25:22 +0900 Subject: [PATCH 199/263] Support Ruby 3.4's new error message format --- test/console/debugger_local_test.rb | 8 ++++---- test/console/info_test.rb | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/console/debugger_local_test.rb b/test/console/debugger_local_test.rb index 14332fba9..f32f43d0c 100644 --- a/test/console/debugger_local_test.rb +++ b/test/console/debugger_local_test.rb @@ -34,7 +34,7 @@ def test_raised_is_accessible_from_repl type "catch Exception" type "c" type "_raised" - assert_line_text(/undefined local variable or method `foo' for main/) + assert_line_text(/undefined local variable or method [`']foo' for main/) type "c" end end @@ -43,7 +43,7 @@ def test_raised_is_accessible_from_command debug_code(program) do type "catch Exception pre: p _raised" type "c" - assert_line_text(/undefined local variable or method `foo' for main/) + assert_line_text(/undefined local variable or method [`']foo' for main/) type "c" end end @@ -96,7 +96,7 @@ def test_raised_doesnt_leak_to_program_binding # stops for NoMethodError because _raised is not defined in the program type "_raised" - assert_line_text(/undefined local variable or method `_raised' for main/) + assert_line_text(/undefined local variable or method [`']_raised' for main/) type "c" end end @@ -155,7 +155,7 @@ def test_raised_doesnt_leak_to_program_binding type "c" # stops for NoMethodError because _return is not defined in the program type "_raised" - assert_line_text(/undefined local variable or method `_return' for main/) + assert_line_text(/undefined local variable or method [`']_return' for main/) type "c" end end diff --git a/test/console/info_test.rb b/test/console/info_test.rb index 85508dd70..972d18103 100644 --- a/test/console/info_test.rb +++ b/test/console/info_test.rb @@ -107,7 +107,7 @@ def test_prints_current_thread type 'b 7' type 'c' type 'info threads' - assert_line_text(/#0 \(sleep\)@.*:7:in `
'/) + assert_line_text(/#0 \(sleep\)@.*:7:in [`']
'/) type 'kill!' end end @@ -257,7 +257,7 @@ def test_info_constant_with_expression_errors type "info constants foo" assert_line_text([ - /eval error: undefined local variable or method `foo' for main/, + /eval error: undefined local variable or method [`']foo' for main/, ]) type "c" From c852422ff7a3fe757581771dcceec8ca276f3ab5 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 19 Feb 2024 18:51:49 +0900 Subject: [PATCH 200/263] Revert "Use `github.sha` when running tests on the master branch" This reverts commit fa52fcde8bf255c515e40b1910287b3dd54b6b19. --- .github/workflows/protocol.yml | 2 +- .github/workflows/ruby-macos.yaml | 2 +- .github/workflows/ruby.yml | 2 +- .github/workflows/test_test.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index cfe560403..984819287 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} jobs: test: diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 5d505fae7..97a072686 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} jobs: test: diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index c3f6e7e2d..c5052e5fd 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} jobs: test: diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index c3955fc20..0a45b7c34 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -15,7 +15,7 @@ env: LAUNCHABLE_ORGANIZATION: "ruby" LAUNCHABLE_WORKSPACE: "debug" # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} jobs: test: From 5568ea01b392c48c2fed701760ed7388a4f0c289 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 19 Feb 2024 18:51:49 +0900 Subject: [PATCH 201/263] Revert "Add comment" This reverts commit 0158b3d6b4d80138609de97ff6cf63830f7612b3. --- test/support/test_case.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index d20f91622..766dc5055 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -11,8 +11,6 @@ require_relative 'assertions' -# Load this library only in the debug CI to prevent LoadError -# when these tests are executed in ruby/ruby. if ENV['LAUNCHABLE_ORGANIZATION'] && ENV['LAUNCHABLE_WORKSPACE'] # "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. require "test/unit/runner/junitxml" From e12791d40be35c517b0bd452b6fbfa082f5fdbaf Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 19 Feb 2024 18:51:49 +0900 Subject: [PATCH 202/263] Revert "require "test/unit/runner/junitxml" if launchable env is configured" This reverts commit 8d205e4296b9e0abbd571b3a5796f478e9bb5093. --- test/support/test_case.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 766dc5055..5725e8df2 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -7,15 +7,12 @@ require 'timeout' require 'json' require 'rbconfig' +# "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. +require "test/unit/runner/junitxml" require_relative '../../lib/debug/client' require_relative 'assertions' -if ENV['LAUNCHABLE_ORGANIZATION'] && ENV['LAUNCHABLE_WORKSPACE'] - # "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. - require "test/unit/runner/junitxml" -end - module DEBUGGER__ class TestCase < Test::Unit::TestCase TestInfo = Struct.new(:queue, :mode, :prompt_pattern, :remote_info, From 69909a332cc4c9a0521c33f9e3bc2478239d085c Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Mon, 19 Feb 2024 18:51:49 +0900 Subject: [PATCH 203/263] Revert "Add launchable integration" This reverts commit 62ea9d1b08ea5c2ed4a681088376fba5e4a85954. --- .github/workflows/protocol.yml | 37 +------------------------------ .github/workflows/ruby-macos.yaml | 37 +------------------------------ .github/workflows/ruby.yml | 37 +------------------------------ .github/workflows/test_test.yml | 37 +------------------------------ Gemfile | 1 - test/support/test_case.rb | 2 -- 6 files changed, 4 insertions(+), 147 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 984819287..755557039 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -6,17 +6,6 @@ on: pull_request: branches: [ master ] -env: - # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 - GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} - # The following envs are necessary in Launchable tokenless authentication. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 - LAUNCHABLE_ORGANIZATION: "ruby" - LAUNCHABLE_WORKSPACE: "debug" - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - jobs: test: @@ -29,27 +18,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - # Set fetch-depth: 0 so that Launchable can receive commits information. - fetch-depth: 0 - # Launchable requires Python and Java - # https://www.launchableinc.com/docs/resources/cli-reference/ - - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Set up JDK 1.8 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '8' - # Setup Launchable - - name: Launchable - install command - run: pip install launchable - - name: Launchable - verify - run: launchable verify - - name: Launchable - record build - run: launchable record build --name ${GITHUB_PR_HEAD_SHA} - - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -59,7 +27,4 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - TESTOPTS="--runner=junitxml --junitxml-output-file=protocol.xml" bundle exec rake test_protocol - - name: Launchable - record tests - run: launchable record tests --flavor test=protocol --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file protocol.xml - if: always() + bundle exec rake test_protocol diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 97a072686..4b04e8647 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -6,17 +6,6 @@ on: pull_request: branches: [ master ] -env: - # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 - GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} - # The following envs are necessary in Launchable tokenless authentication. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 - LAUNCHABLE_ORGANIZATION: "ruby" - LAUNCHABLE_WORKSPACE: "debug" - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - jobs: test: @@ -29,27 +18,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - # Set fetch-depth: 0 so that Launchable can receive commits information. - fetch-depth: 0 - # Launchable requires Python and Java - # https://www.launchableinc.com/docs/resources/cli-reference/ - - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Set up JDK 1.8 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '8' - # Setup Launchable - - name: Launchable - install command - run: pip install launchable - - name: Launchable - verify - run: launchable verify - - name: Launchable - record build - run: launchable record build --name ${GITHUB_PR_HEAD_SHA} - - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -59,7 +27,4 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - TESTOPTS="--runner=junitxml --junitxml-output-file=ruby-macos.xml" bundle exec rake test_console - - name: launchable record tests - run: launchable record tests --flavor test=console --flavor os=macos-latest --flavor ruby=${{ matrix.ruby-version }} file ruby-macos.xml - if: always() + bundle exec rake test_console diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index c5052e5fd..dd76ced54 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -6,17 +6,6 @@ on: pull_request: branches: [ master ] -env: - # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 - GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} - # The following envs are necessary in Launchable tokenless authentication. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 - LAUNCHABLE_ORGANIZATION: "ruby" - LAUNCHABLE_WORKSPACE: "debug" - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - jobs: test: @@ -29,27 +18,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - # Set fetch-depth: 0 so that Launchable can receive commits information. - fetch-depth: 0 - # Launchable requires Python and Java - # https://www.launchableinc.com/docs/resources/cli-reference/ - - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Set up JDK 1.8 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '8' - # Setup Launchable - - name: Launchable - install command - run: pip install launchable - - name: Launchable - verify - run: launchable verify - - name: Launchable - record build - run: launchable record build --name ${GITHUB_PR_HEAD_SHA} - - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -59,7 +27,4 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - TESTOPTS="--runner=junitxml --junitxml-output-file=ruby.xml" bundle exec rake test_console - - name: launchable record tests - run: launchable record tests --flavor test=console --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file ruby.xml - if: always() + bundle exec rake test_console diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 0a45b7c34..3123697fe 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -6,17 +6,6 @@ on: pull_request: branches: [ master ] -env: - # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 - GITHUB_PULL_REQUEST_URL: ${{ github.event.pull_request.html_url }} - # The following envs are necessary in Launchable tokenless authentication. - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 - LAUNCHABLE_ORGANIZATION: "ruby" - LAUNCHABLE_WORKSPACE: "debug" - # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 - GITHUB_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} - jobs: test: @@ -29,27 +18,6 @@ jobs: steps: - uses: actions/checkout@v4 - with: - # Set fetch-depth: 0 so that Launchable can receive commits information. - fetch-depth: 0 - # Launchable requires Python and Java - # https://www.launchableinc.com/docs/resources/cli-reference/ - - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Set up JDK 1.8 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' - java-version: '8' - # Setup Launchable - - name: Launchable - install command - run: pip install launchable - - name: Launchable - verify - run: launchable verify - - name: Launchable - record build - run: launchable record build --name ${GITHUB_PR_HEAD_SHA} - - name: Set up Ruby uses: ruby/setup-ruby@v1 with: @@ -59,7 +27,4 @@ jobs: run: | bundle exec rake clobber bundle exec rake compile - TESTOPTS="--runner=junitxml --junitxml-output-file=test_test.xml" bundle exec rake test_test - - name: launchable record tests - run: launchable record tests --flavor test=test-framework --flavor os=ubuntu-latest --flavor ruby=${{ matrix.ruby-version }} file test_test.xml - if: always() + bundle exec rake test_test diff --git a/Gemfile b/Gemfile index 50630d1e8..c59ccbe1a 100644 --- a/Gemfile +++ b/Gemfile @@ -7,4 +7,3 @@ gem "rake-compiler" gem "test-unit", "~> 3.0" gem "test-unit-rr" gem "json-schema" -gem "test-unit-runner-junitxml" diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5725e8df2..fae5b9f58 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -7,8 +7,6 @@ require 'timeout' require 'json' require 'rbconfig' -# "test/unit/runner/junitxml" is used for reporting test result in JUnit XML format. -require "test/unit/runner/junitxml" require_relative '../../lib/debug/client' require_relative 'assertions' From 9c389d913ab501263dbef36a682fda6e27c44149 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Tue, 20 Feb 2024 04:45:00 +0900 Subject: [PATCH 204/263] catch up ruby 3.4.0 error related changes * should use `base_label` instead of `label`. * should accept both backtick or single quote * shoudl accept with class name --- lib/debug/thread_client.rb | 4 ++-- test/protocol/boot_config_raw_dap_test.rb | 4 ++-- test/protocol/threads_test.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 753898560..6d8cf3f2c 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -989,7 +989,7 @@ def wait_next_action_ true else true if depth >= DEBUGGER__.frame_depth - 3 && - caller_locations(2, 1).first.label == target_location_label + caller_locations(2, 1).first.base_label == target_location_label # TODO: imcomplete condition end end @@ -1005,7 +1005,7 @@ def wait_next_action_ true if pat === tp.callee_id.to_s else # :return, :b_return true if depth >= DEBUGGER__.frame_depth - 3 && - caller_locations(2, 1).first.label == target_location_label + caller_locations(2, 1).first.base_label == target_location_label # TODO: imcomplete condition end end diff --git a/test/protocol/boot_config_raw_dap_test.rb b/test/protocol/boot_config_raw_dap_test.rb index dd32e790a..677becd63 100644 --- a/test/protocol/boot_config_raw_dap_test.rb +++ b/test/protocol/boot_config_raw_dap_test.rb @@ -120,7 +120,7 @@ def test_boot_configuration_works_correctly threads: [ { id: 1, - name: "#1 #{temp_file_path}:1:in `
'" + name: /\#1 #{temp_file_path}:1:in [`']
'/ } ] } @@ -141,7 +141,7 @@ def test_boot_configuration_works_correctly threads: [ { id: 1, - name: "#1 #{temp_file_path}:1:in `
'" + name: /\#1 #{temp_file_path}:1:in [`']
'/ } ] } diff --git a/test/protocol/threads_test.rb b/test/protocol/threads_test.rb index dc97bad1f..b27a4229f 100644 --- a/test/protocol/threads_test.rb +++ b/test/protocol/threads_test.rb @@ -20,8 +20,8 @@ def test_reponse_returns_correct_threads_info assert_threads_result( [ - /\.rb:\d:in `
'/, - /\.rb:\d:in `block in foo'/ + /\.rb:\d:in [`']
'/, + /\.rb:\d:in [`']block in (Object#)?foo'/ ] ) From b0b95347b13b6ce7c3d3c12e2ea9e5a73ab39bf2 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 29 Jan 2024 14:26:04 +0100 Subject: [PATCH 205/263] Fix syntax warnings ``` $ ruby -W -c lib/debug/server_cdp.rb lib/debug/server_cdp.rb:134: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator lib/debug/server_cdp.rb:161: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator lib/debug/server_cdp.rb:193: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator lib/debug/server_cdp.rb:300: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator lib/debug/server_cdp.rb:381: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator lib/debug/server_cdp.rb:661: warning: ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator Syntax OK ``` --- lib/debug/server_cdp.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index d4e012fe2..ef265b818 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -131,7 +131,7 @@ def run_new_chrome stdout.close data = stderr.readpartial 4096 stderr.close - if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/ + if data.match(/DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/) port = $1 path = $2 end @@ -158,7 +158,7 @@ def run_new_chrome raise NotFoundChromeEndpointError end stderr.close - if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/ + if data.match(/DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/) port = $1 path = $2 end @@ -190,7 +190,7 @@ def get_devtools_endpoint tf while i < ITERATIONS i += 1 if File.exist?(tf) && data = File.read(tf) - if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/ + if data.match(/DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/) port = $1 path = $2 return [port, path] @@ -297,7 +297,7 @@ def handshake port, path res = @sock.readpartial 4092 show_protocol :<, res - if res.match /^Sec-WebSocket-Accept: (.*)\r\n/ + if res.match(/^Sec-WebSocket-Accept: (.*)\r\n/) correct_key = Base64.strict_encode64 Digest::SHA1.digest "#{key}==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" raise "The Sec-WebSocket-Accept value: #{$1} is not valid" unless $1 == correct_key else @@ -378,7 +378,7 @@ def handshake req = @sock.readpartial 4096 show_protocol '>', req - if req.match /^Sec-WebSocket-Key: (.*)\r\n/ + if req.match(/^Sec-WebSocket-Key: (.*)\r\n/) accept = Base64.strict_encode64 Digest::SHA1.digest "#{$1}258EAFA5-E914-47DA-95CA-C5AB0DC85B11" res = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: #{accept}\r\n\r\n" @sock.print res @@ -658,7 +658,7 @@ def get_source_code path def activate_bp bps bps.each_key{|k| - if k.match /^\d+:(\d+):(.*)/ + if k.match(/^\d+:(\d+):(.*)/) line = $1 path = $2 SESSION.add_line_breakpoint(path, line.to_i + 1) From 47bb58b983e1ae52b21a11a2d46422aa0d155665 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Tue, 20 Feb 2024 10:48:15 +0100 Subject: [PATCH 206/263] Drop base64 dependency (#1071) See #1066 Co-authored-by: Koichi Sasada --- debug.gemspec | 1 - lib/debug/server_cdp.rb | 5 ++--- test/support/protocol_test_case.rb | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/debug.gemspec b/debug.gemspec index b0d0f7139..2a5891f32 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -29,5 +29,4 @@ Gem::Specification.new do |spec| spec.add_dependency "irb", "~> 1.10" # for irb:debug integration spec.add_dependency "reline", ">= 0.3.8" - spec.add_dependency "base64" end diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index ef265b818..3826f1242 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -2,7 +2,6 @@ require 'json' require 'digest/sha1' -require 'base64' require 'securerandom' require 'stringio' require 'open3' @@ -298,7 +297,7 @@ def handshake port, path show_protocol :<, res if res.match(/^Sec-WebSocket-Accept: (.*)\r\n/) - correct_key = Base64.strict_encode64 Digest::SHA1.digest "#{key}==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + correct_key = Digest::SHA1.base64digest "#{key}==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" raise "The Sec-WebSocket-Accept value: #{$1} is not valid" unless $1 == correct_key else raise "Unknown response: #{res}" @@ -379,7 +378,7 @@ def handshake show_protocol '>', req if req.match(/^Sec-WebSocket-Key: (.*)\r\n/) - accept = Base64.strict_encode64 Digest::SHA1.digest "#{$1}258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + accept = Digest::SHA1.base64digest "#{$1}258EAFA5-E914-47DA-95CA-C5AB0DC85B11" res = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: #{accept}\r\n\r\n" @sock.print res show_protocol :<, res diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 902955c0d..429640fb8 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -1,7 +1,6 @@ require 'net/http' require 'uri' require 'digest/sha1' -require 'base64' require_relative 'test_case' require_relative 'dap_utils' @@ -924,7 +923,7 @@ def handshake port, uuid @sock.print "GET /#{uuid} HTTP/1.1\r\nHost: 127.0.0.1:#{port}\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: #{key}==\r\n\r\n" server_key = get_server_key - correct_key = Base64.strict_encode64 Digest::SHA1.digest "#{key}==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + correct_key = Digest::SHA1.base64digest "#{key}==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" raise "The Sec-WebSocket-Accept value: #{$1} is not valid" unless server_key == correct_key end From e4e6545ebdb67e04997068c37f9394f2c0644586 Mon Sep 17 00:00:00 2001 From: James Adam Date: Tue, 30 Jan 2024 20:59:43 +0000 Subject: [PATCH 207/263] Fix ENOENT error when running tests under Rails Under Ruby 3.3, without this change, running tests under Rails using the `bin/rails test` command fails. The failure can be expressed in two ways. If a whole test file is being run (e.g. `bin/rails test test/models/thing_test.rb`, then it looks like the whole contents of the file are being passed to rdbg: ``` (rdbg) nil (rdbg) (rdbg) false (rdbg) (rdbg) eval error: (rdbg)//private/tmp/thing/test/models/thing_test.rb:1: syntax error, unexpected end-of-input, expecting ';' or '\n' ...gTest < ActiveSupport::TestCase ... ^ nil (rdbg) eval error: (rdbg)//private/tmp/thing/test/models/thing_test.rb:1: syntax error, unexpected end-of-input test "stuff" do ^ nil (rdbg) # (rdbg) true (rdbg) eval error: (rdbg)//private/tmp/thing/test/models/thing_test.rb:1: syntax error, unexpected `end' nil (rdbg) eval error: (rdbg)//private/tmp/thing/test/models/thing_test.rb:1: syntax error, unexpected `end' nil (rdbg) Really quit? [Y/n] ``` If a specific line is passed (e.g. `bin/rails test test/models/thing.rb:4`), then the failure is different: ``` (rdbg) # terminated with exception (report_on_exception is true): /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets': No such file or directory @ rb_sysopen - test/models/thing_test.rb:6 (Errno::ENOENT) from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `readline' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:78:in `block in readline' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:90:in `block in setup_interrupt' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:1981:in `intercept_trap_sigint' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:83:in `setup_interrupt' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:77:in `readline' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:444:in `wait_command' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:404:in `block in wait_command_loop' from :187:in `loop' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:403:in `wait_command_loop' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:329:in `process_event' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:254:in `session_server_main' from /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:212:in `block in activate' nil # @@@ # > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1251:in `backtrace' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1251:in `block in wait_next_action_' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1249:in `each' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1249:in `rescue in wait_next_action_' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1244:in `wait_next_action_' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:875:in `block in wait_next_action' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:866:in `block in fiber_blocking' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:866:in `blocking' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:866:in `fiber_blocking' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:875:in `wait_next_action' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:320:in `suspend' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:251:in `on_breakpoint' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/breakpoint.rb:69:in `suspend' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/breakpoint.rb:170:in `block in setup' > /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:2633:in `debugger' > /private/tmp/thing/test/models/thing_test.rb:7:in `block in ' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:94:in `block (3 levels) in run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:191:in `capture_exceptions' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:89:in `block (2 levels) in run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:303:in `time_it' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:88:in `block in run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:412:in `on_signal' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:239:in `with_info_handler' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest/test.rb:87:in `run' > /Users/james/.gem/ruby/3.3.0/gems/activesupport-7.1.3/lib/active_support/executor/test_helper.rb:5:in `block in run' > /Users/james/.gem/ruby/3.3.0/gems/activesupport-7.1.3/lib/active_support/execution_wrapper.rb:105:in `perform' > /Users/james/.gem/ruby/3.3.0/gems/activesupport-7.1.3/lib/active_support/executor/test_helper.rb:5:in `run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:1126:in `run_one_method' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:378:in `run_one_method' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:365:in `block (2 levels) in run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:364:in `each' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:364:in `block in run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:412:in `on_signal' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:399:in `with_info_handler' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:363:in `run' > /Users/james/.gem/ruby/3.3.0/gems/railties-7.1.3/lib/rails/test_unit/line_filtering.rb:10:in `run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:185:in `block in __run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:185:in `map' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:185:in `__run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:162:in `run' > /Users/james/.gem/ruby/3.3.0/gems/minitest-5.21.2/lib/minitest.rb:86:in `block in autorun' @@@ # > /Users/james/.gem/ruby/3.3.0/gems/activerecord-7.1.3/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb:48:in `sleep' > /Users/james/.gem/ruby/3.3.0/gems/activerecord-7.1.3/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb:48:in `block in spawn_thread' ["DEBUGGER Exception: /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/thread_client.rb:1255", #, ["/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `readline'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:78:in `block in readline'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:90:in `block in setup_interrupt'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:1981:in `intercept_trap_sigint'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:83:in `setup_interrupt'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:77:in `readline'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:444:in `wait_command'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:404:in `block in wait_command_loop'", ":187:in `loop'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:403:in `wait_command_loop'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:329:in `process_event'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:254:in `session_server_main'", "/Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:212:in `block in activate'"]] E Error: ThingTest#test_stuff: Errno::ENOENT: No such file or directory @ rb_sysopen - test/models/thing_test.rb:6 /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `gets' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/console.rb:146:in `readline' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:78:in `block in readline' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:90:in `block in setup_interrupt' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:1981:in `intercept_trap_sigint' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:83:in `setup_interrupt' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/local.rb:77:in `readline' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:444:in `wait_command' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:404:in `block in wait_command_loop' :187:in `loop' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:403:in `wait_command_loop' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:329:in `process_event' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:254:in `session_server_main' /Users/james/.gem/ruby/3.3.0/gems/debug-1.9.1/lib/debug/session.rb:212:in `block in activate' ``` Either way, making this change seems to fix it. The error is very reminiscent of that described in https://github.com/ruby/debug/issues/156, where a similar fix was required. --- lib/debug/console.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index 53545e5e9..b228086d9 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -143,7 +143,7 @@ def history rescue LoadError def readline prompt print prompt - gets + $stdin.gets end def history From 315ecaf5a0e809e7436b9934ae7c362c05c0efa0 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 22 Jan 2024 13:15:23 +0900 Subject: [PATCH 208/263] Remove and Restore irb configuration like irbrc while irb console tests --- test/console/irb_test.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb index 478a37036..d52094d16 100644 --- a/test/console/irb_test.rb +++ b/test/console/irb_test.rb @@ -6,11 +6,20 @@ module DEBUGGER__ class IrbTest < ConsoleTestCase def setup @original_pager = ENV["PAGER"] + @original_home = ENV["HOME"] + @original_xdg_config_home = ENV["XDG_CONFIG_HOME"] + @original_irbrc = ENV["IRBRC"] + ENV["PAGER"] = "cat" + ENV["HOME"] = ENV["XDG_CONFIG_HOME"] = Dir.mktmpdir + ENV["IRBRC"] = nil end def teardown ENV["PAGER"] = @original_pager + ENV["HOME"] = @original_home + ENV["XDG_CONFIG_HOME"] = @original_xdg_config_home + ENV["IRBRC"] = @original_irbrc end def program From 2d602636d99114d55a32fedd652c9c704446a749 Mon Sep 17 00:00:00 2001 From: m-nakamura145 Date: Fri, 19 Jan 2024 09:18:19 +0900 Subject: [PATCH 209/263] Use ruby/actions workflow for ruby versions --- .github/workflows/protocol.yml | 11 +++++++++-- .github/workflows/ruby-macos.yaml | 10 ++++++++-- .github/workflows/ruby.yml | 11 +++++++++-- .github/workflows/test_test.yml | 11 +++++++++-- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 755557039..3b61c026c 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -7,14 +7,21 @@ on: branches: [ master ] jobs: - test: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 2.7 + versions: '["debug"]' + test: + needs: ruby-versions runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "3.2", "3.3", "head", "debug"] + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.versions) }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 4b04e8647..4e17a3370 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -7,14 +7,20 @@ on: branches: [ master ] jobs: - test: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 3.2 + test: + needs: ruby-versions runs-on: macos-latest timeout-minutes: 15 strategy: fail-fast: false matrix: - ruby-version: ["3.2", "3.3", "head"] + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.versions) }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index dd76ced54..56d5d0681 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -7,14 +7,21 @@ on: branches: [ master ] jobs: - test: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 2.7 + versions: '["debug"]' + test: + needs: ruby-versions runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: - ruby-version: ["2.7", "3.0", "3.1", "3.2", "3.3", "head", "debug"] + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.versions) }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 3123697fe..58b1580e7 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -7,14 +7,21 @@ on: branches: [ master ] jobs: - test: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + engine: cruby + min_version: 3.0 + versions: '["debug"]' + test: + needs: ruby-versions runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: - ruby-version: ["3.0", "3.1", "3.2", "3.3", "head", "debug"] + ruby-version: ${{ fromJson(needs.ruby-versions.outputs.versions) }} steps: - uses: actions/checkout@v4 From 935f903e242438134af5ced9ff414a177b42dd89 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Tue, 2 Jan 2024 13:20:39 +0000 Subject: [PATCH 210/263] Make irb_console toggleable with config update 1. When the user sets `irb_console` to `true` through the command, the `irb:rdbg` will now be enabled the same way as typing the `irb` command. 2. When the user sets `irb_console` to `false` through the command, the `irb:rdbg` will now be disabled. 3. Users can now enable `irb:rdbg` by setting `irb_console` to `true` in their `.rdbgrc` file. --- lib/debug/config.rb | 20 ++++++++++++++++++++ lib/debug/session.rb | 22 +++++++++++++++------- lib/debug/thread_client.rb | 3 --- test/console/irb_test.rb | 26 ++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index ab4c9c559..eb132ce4a 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -158,6 +158,26 @@ def update conf SESSION.set_no_sigint_hook old, new end end + + if_updated old_conf, conf, :irb_console do |old, new| + if defined?(SESSION) && SESSION.active? + # irb_console is switched from true to false + if old + Reline.completion_proc = nil + Reline.output_modifier_proc = nil + Reline.autocompletion = false + Reline.dig_perfect_match_proc = nil + SESSION.reset_ui UI_LocalConsole.new + # irb_console is switched from false to true + else + if CONFIG[:open] + SESSION.instance_variable_get(:@ui).puts "\nIRB is not supported on the remote console." + else + SESSION.activate_irb_integration + end + end + end + end end private def if_updated old_conf, new_conf, key diff --git a/lib/debug/session.rb b/lib/debug/session.rb index c5b410182..05dc7f508 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -202,11 +202,6 @@ def activate ui = nil, on_fork: false end @tp_thread_end.enable - if CONFIG[:irb_console] && !CONFIG[:open] - require_relative "irb_integration" - thc.activate_irb_integration - end - # session start q << true session_server_main @@ -214,6 +209,12 @@ def activate ui = nil, on_fork: false first_q << :ok q.pop + + # For activating irb:rdbg with startup config like `RUBY_DEBUG_IRB_CONSOLE=1` + # Because in that case the `Config#if_updated` callback would not be triggered + if CONFIG[:irb_console] && !CONFIG[:open] + activate_irb_integration + end end def deactivate @@ -942,10 +943,11 @@ def register_default_command register_command 'irb' do |arg| if @ui.remote? @ui.puts "\nIRB is not supported on the remote console." - :retry else - request_eval :irb, nil + config_set :irb_console, true end + + :retry end ### Trace @@ -1876,6 +1878,12 @@ def check_unsafe end end + def activate_irb_integration + require_relative "irb_integration" + thc = get_thread_client(@session_server) + thc.activate_irb_integration + end + def enter_postmortem_session exc return unless exc.instance_variable_defined? :@__debugger_postmortem_frames diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 6d8cf3f2c..80a434b0c 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1056,9 +1056,6 @@ def wait_next_action_ end when :call result = frame_eval(eval_src) - when :irb - require_relative "irb_integration" - activate_irb_integration when :display, :try_display failed_results = [] eval_src.each_with_index{|src, i| diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb index d52094d16..857d02dfd 100644 --- a/test/console/irb_test.rb +++ b/test/console/irb_test.rb @@ -35,6 +35,12 @@ def test_irb_command_is_disabled_in_remote_mode assert_line_text 'IRB is not supported on the remote console.' type 'q!' end + + debug_code(program, remote: :remote_only) do + type 'config set irb_console true' + assert_line_text 'IRB is not supported on the remote console.' + type 'q!' + end end def test_irb_command_switches_console_to_irb @@ -47,6 +53,11 @@ def test_irb_command_switches_console_to_irb type 'next' type 'info' assert_line_text([/a = 1/, /b = nil/]) + + # disable irb console + type 'config set irb_console false' + type '456' + assert_raw_line_text '(rdbg) 456' type 'q!' end end @@ -62,10 +73,25 @@ def test_irb_console_config_activates_irb type 'next' type 'info' assert_line_text([/a = 1/, /b = nil/]) + + # disable irb console + type 'config set irb_console false' + type '456' + assert_raw_line_text '(rdbg) 456' type 'q!' end ensure ENV["RUBY_DEBUG_IRB_CONSOLE"] = nil end + + private + + # assert_line_text ignores the prompt line, so we can't use it to assert the prompt transition + # assert_raw_line_text is a workaround for that + def assert_raw_line_text(expectation) + @scenario.push(Proc.new do |test_info| + assert_include(test_info.last_backlog.join, expectation) + end) + end end end From 68f7753c024d48e78b6519d790edca048bb2a850 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 21 Feb 2024 20:49:44 +0800 Subject: [PATCH 211/263] Add Session#deactivate_irb_integration --- lib/debug/config.rb | 6 +----- lib/debug/irb_integration.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index eb132ce4a..86b9bfdc9 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -163,11 +163,7 @@ def update conf if defined?(SESSION) && SESSION.active? # irb_console is switched from true to false if old - Reline.completion_proc = nil - Reline.output_modifier_proc = nil - Reline.autocompletion = false - Reline.dig_perfect_match_proc = nil - SESSION.reset_ui UI_LocalConsole.new + SESSION.deactivate_irb_integration # irb_console is switched from false to true else if CONFIG[:open] diff --git a/lib/debug/irb_integration.rb b/lib/debug/irb_integration.rb index a2ea34b65..3fc92ea61 100644 --- a/lib/debug/irb_integration.rb +++ b/lib/debug/irb_integration.rb @@ -24,4 +24,14 @@ def activate_irb_integration IRB::Context.prepend(IrbPatch) end end + + class Session + def deactivate_irb_integration + Reline.completion_proc = nil + Reline.output_modifier_proc = nil + Reline.autocompletion = false + Reline.dig_perfect_match_proc = nil + reset_ui UI_LocalConsole.new + end + end end From 98dad005db9053f5d2a9965483d550a477ba6d5c Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 10 Mar 2024 21:20:51 +0900 Subject: [PATCH 212/263] Separate setup and execution steps in CI --- .github/workflows/protocol.yml | 5 +++-- .github/workflows/ruby-macos.yaml | 5 +++-- .github/workflows/ruby.yml | 5 +++-- .github/workflows/test_test.yml | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 3b61c026c..7eb8aff6c 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -30,8 +30,9 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run tests + - name: Set up tests run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_protocol + - name: Run tests + run: bundle exec rake test_protocol diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 4e17a3370..01655e9b9 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -29,8 +29,9 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run tests + - name: Set up tests run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_console + - name: Run tests + run: bundle exec rake test_console diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 56d5d0681..fb99a1d7d 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -30,8 +30,9 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run tests + - name: Set up tests run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_console + - name: Run tests + run: bundle exec rake test_console diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 58b1580e7..2aba0cb1f 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -30,8 +30,9 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true - - name: Run tests + - name: Set up tests run: | bundle exec rake clobber bundle exec rake compile - bundle exec rake test_test + - name: Run tests + run: bundle exec rake test_test From 3564601e40798e65c912dc554347a8fa8ac9341b Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Sun, 10 Mar 2024 21:42:18 +0900 Subject: [PATCH 213/263] Fix flakey test "test_reponse_returns_correct_threads_info" --- test/protocol/catch_test.rb | 4 ++-- test/protocol/eval_test.rb | 2 +- test/support/protocol_test_case.rb | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/protocol/catch_test.rb b/test/protocol/catch_test.rb index 48ecf524b..b1749b59e 100644 --- a/test/protocol/catch_test.rb +++ b/test/protocol/catch_test.rb @@ -26,14 +26,14 @@ def test_set_exception_breakpoints_unsets_exception_breakpoints run_protocol_scenario PROGRAM, cdp: false do req_set_exception_breakpoints([{ name: "RuntimeError" }]) req_set_exception_breakpoints([]) - req_continue + req_terminate_debuggee end end def test_set_exception_breakpoints_accepts_condition run_protocol_scenario PROGRAM, cdp: false do req_set_exception_breakpoints([{ name: "RuntimeError", condition: "a == 2" }]) - req_continue + req_terminate_debuggee end run_protocol_scenario PROGRAM, cdp: false do diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index c8b03fec9..5f32358f2 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -77,7 +77,7 @@ def test_eval_with_threads req_add_breakpoint 9 req_continue assert_repl_result({value: 'false', type: 'FalseClass'}, 'm.lock.nil?', frame_idx: 0) - req_continue + req_terminate_debuggee end end end diff --git a/test/support/protocol_test_case.rb b/test/support/protocol_test_case.rb index 429640fb8..78e0b5bb0 100644 --- a/test/support/protocol_test_case.rb +++ b/test/support/protocol_test_case.rb @@ -111,6 +111,7 @@ def req_continue case get_target_ui when 'vscode' send_dap_request 'continue', threadId: 1 + find_response :event, 'stopped', 'V Date: Mon, 11 Mar 2024 10:55:16 +0900 Subject: [PATCH 214/263] Add Launchable in CI --- .github/actions/launchable/setup/action.yaml | 79 ++++++++++++++++++++ .github/workflows/protocol.yml | 8 ++ .github/workflows/ruby-macos.yaml | 8 ++ .github/workflows/ruby.yml | 8 ++ .github/workflows/test_test.yml | 8 ++ Gemfile | 1 + test/support/test_case.rb | 7 ++ 7 files changed, 119 insertions(+) create mode 100644 .github/actions/launchable/setup/action.yaml diff --git a/.github/actions/launchable/setup/action.yaml b/.github/actions/launchable/setup/action.yaml new file mode 100644 index 000000000..b5c0c920f --- /dev/null +++ b/.github/actions/launchable/setup/action.yaml @@ -0,0 +1,79 @@ +name: Set up Launchable +description: >- + Install the required dependencies and execute the necessary Launchable commands for test recording + +inputs: + report-path: + default: launchable_reports.json + required: true + description: The file path of the test report for uploading to Launchable + + test-task: + default: none + required: true + description: >- + Test task that determine how tests are run. + This value is used in the Launchable flavor. + +runs: + using: composite + + steps: + - name: Enable Launchable conditionally + id: enable-launchable + run: echo "enable-launchable=true" >> $GITHUB_OUTPUT + shell: bash + if: ${{ github.repository == 'ruby/debug' }} + + # Launchable CLI requires Python and Java. + # https://www.launchableinc.com/docs/resources/cli-reference/ + - name: Set up Python + uses: actions/setup-python@871daa956ca9ea99f3c3e30acb424b7960676734 # v5.0.0 + with: + python-version: "3.x" + if: ${{ steps.enable-launchable.outputs.enable-launchable }} + + - name: Set up Java + uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0 + with: + distribution: 'temurin' + java-version: '17' + if: ${{ steps.enable-launchable.outputs.enable-launchable }} + + - name: Set environment variables for Launchable + shell: bash + run: | + : # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App. + : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42 + echo "GITHUB_PULL_REQUEST_URL=${{ github.event.pull_request.html_url }}" >> $GITHUB_ENV + : # The following envs are necessary in Launchable tokenless authentication. + : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20 + echo "LAUNCHABLE_ORGANIZATION=${{ github.repository_owner }}" >> $GITHUB_ENV + echo "LAUNCHABLE_WORKSPACE=${{ github.event.repository.name }}" >> $GITHUB_ENV + : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71 + echo "GITHUB_PR_HEAD_SHA=${{ github.event.pull_request.head.sha || github.sha }}" >> $GITHUB_ENV + if: ${{ steps.enable-launchable.outputs.enable-launchable }} + + - name: Set up Launchable + shell: bash + run: | + set -x + PATH=$PATH:$(python -msite --user-base)/bin + echo "PATH=$PATH" >> $GITHUB_ENV + pip install --user launchable + launchable verify + : # The build name cannot include a slash, so we replace the string here. + github_ref="${{ github.ref }}" + github_ref="${github_ref//\//_}" + launchable record build --name ${github_ref}_${GITHUB_PR_HEAD_SHA} + echo "TESTOPTS=${TESTOPTS} --runner=launchable --launchable-test-report-json=${{ inputs.report-path }}" >> $GITHUB_ENV + if: ${{ steps.enable-launchable.outputs.enable-launchable }} + + - name: Record test results in Launchable + uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0 + with: + shell: bash + post: | + launchable record tests --flavor os=${{ inputs.os }} --flavor test_task=${{ inputs.test-task }} raw ${{ inputs.report-path }} + rm -f ${{ inputs.report-path }} + if: ${{ always() && steps.enable-launchable.outputs.enable-launchable }} diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index 7eb8aff6c..fb9c3b204 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -25,6 +25,14 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 10 so that Launchable can receive commits information. + fetch-depth: 10 + - name: Set up Launchable + uses: ./.github/actions/launchable/setup + with: + os: ubuntu-latest + test-task: test_protocol - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 01655e9b9..6e4d6bc06 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -24,6 +24,14 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 10 so that Launchable can receive commits information. + fetch-depth: 10 + - name: Set up Launchable + uses: ./.github/actions/launchable/setup + with: + os: macos-latest + test-task: test_console - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index fb99a1d7d..2666dc282 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -25,6 +25,14 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 10 so that Launchable can receive commits information. + fetch-depth: 10 + - name: Set up Launchable + uses: ./.github/actions/launchable/setup + with: + os: ubuntu-latest + test-task: test_console - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index 2aba0cb1f..f4339bf35 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -25,6 +25,14 @@ jobs: steps: - uses: actions/checkout@v4 + with: + # Set fetch-depth: 10 so that Launchable can receive commits information. + fetch-depth: 10 + - name: Set up Launchable + uses: ./.github/actions/launchable/setup + with: + os: ubuntu-latest + test-task: test_test - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/Gemfile b/Gemfile index c59ccbe1a..ae1e1228c 100644 --- a/Gemfile +++ b/Gemfile @@ -7,3 +7,4 @@ gem "rake-compiler" gem "test-unit", "~> 3.0" gem "test-unit-rr" gem "json-schema" +gem "test-unit-launchable" diff --git a/test/support/test_case.rb b/test/support/test_case.rb index fae5b9f58..5ff8a2e27 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -11,6 +11,13 @@ require_relative 'assertions' +# Load this library only in the debug CI to prevent LoadError +# when these tests are executed in ruby/ruby. +if ENV['LAUNCHABLE_ORGANIZATION'] && ENV['LAUNCHABLE_WORKSPACE'] + # "test/unit/runner/launchable" is used for uploading test result to Launchable. + require "test/unit/runner/launchable" +end + module DEBUGGER__ class TestCase < Test::Unit::TestCase TestInfo = Struct.new(:queue, :mode, :prompt_pattern, :remote_info, From 75326e28e1b130b61fb8cd138e134641768de607 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Wed, 27 Mar 2024 11:31:47 -0400 Subject: [PATCH 215/263] Fix name of rb_iseq_t struct Only `struct rb_iseq_struct`` and `rb_iseq_t`` are valid names, `struct rb_iseq` is not a valid name. --- ext/debug/debug.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index ad8431cef..5404c92d2 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -121,26 +121,26 @@ frame_depth(VALUE self) // iseq -const struct rb_iseq *rb_iseqw_to_iseq(VALUE iseqw); +const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw); #ifdef HAVE_RB_ISEQ_TYPE -VALUE rb_iseq_type(const struct rb_iseq *); +VALUE rb_iseq_type(const rb_iseq_t *); static VALUE iseq_type(VALUE iseqw) { - const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw); + const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw); return rb_iseq_type(iseq); } #endif #ifdef HAVE_RB_ISEQ_PARAMETERS -VALUE rb_iseq_parameters(const struct rb_iseq *, int is_proc); +VALUE rb_iseq_parameters(const rb_iseq_t *, int is_proc); static VALUE iseq_parameters_symbols(VALUE iseqw) { - const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw); + const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw); VALUE params = rb_iseq_parameters(iseq, 0); VALUE ary = rb_ary_new(); @@ -167,12 +167,12 @@ iseq_parameters_symbols(VALUE iseqw) #endif #ifdef HAVE_RB_ISEQ_CODE_LOCATION -void rb_iseq_code_location(const struct rb_iseq *, int *first_lineno, int *first_column, int *last_lineno, int *last_column); +void rb_iseq_code_location(const rb_iseq_t *, int *first_lineno, int *first_column, int *last_lineno, int *last_column); static VALUE iseq_first_line(VALUE iseqw) { - const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw); + const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw); int line; rb_iseq_code_location(iseq, &line, NULL, NULL, NULL); return INT2NUM(line); @@ -181,7 +181,7 @@ iseq_first_line(VALUE iseqw) static VALUE iseq_last_line(VALUE iseqw) { - const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw); + const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw); int line; rb_iseq_code_location(iseq, NULL, NULL, &line, NULL); return INT2NUM(line); From ffbdb30fdd958e2a9a66d84fd1c235a82425746b Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Wed, 27 Mar 2024 11:33:17 -0400 Subject: [PATCH 216/263] Use rb_iseqw_to_iseq to get iseq pointer Using DATA_PTR is internal implementation details so we should not use it. --- ext/debug/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/debug/debug.c b/ext/debug/debug.c index 5404c92d2..b27263d46 100644 --- a/ext/debug/debug.c +++ b/ext/debug/debug.c @@ -8,13 +8,13 @@ static VALUE rb_mDebugger; // iseq typedef struct rb_iseq_struct rb_iseq_t; +const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw); VALUE rb_iseq_realpath(const rb_iseq_t *iseq); static VALUE iseq_realpath(VALUE iseqw) { - rb_iseq_t *iseq = DATA_PTR(iseqw); - return rb_iseq_realpath(iseq); + return rb_iseq_realpath(rb_iseqw_to_iseq(iseqw)); } static VALUE rb_cFrameInfo; From a655f10fd51eec1f431e29b998cc25c0d5b7c974 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 20 Mar 2024 21:10:54 +0000 Subject: [PATCH 217/263] Mention IRB as the console in readme --- README.md | 24 ++++++++++++++++++++++++ misc/README.md.erb | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/README.md b/README.md index 040bba498..f6cf08010 100644 --- a/README.md +++ b/README.md @@ -784,6 +784,30 @@ The `<...>` notation means the argument. * Show help for the given command. +### Using IRB as the Debug Console + +Starting from version `v1.9`, you can now use IRB as the debug console. This integration brings additional features such as: + +* Autocompletion +* Support for multi-line input +* Access to commands not available in `debug`, like `show_source` or `show_doc` +* [Configurable command aliases](https://docs.ruby-lang.org/en/master/IRB.html#module-IRB-label-Command+Aliases) + +To switch to the IRB console, simply use the `irb` command in the debug console. + +Once activated, you'll notice the prompt changes to: + +```txt +irb:rdbg(main):001> +``` + +If you want to make IRB the default console for all sessions, configure the `irb_console` setting by either: + +* Setting the `RUBY_DEBUG_IRB_CONSOLE=true` environment variable +* Or adding `config set irb_console 1` to your `~/.rdbgrc` + +To disable the IRB console in the current session, execute `config set irb_console 0` in the console. + ## Debugger API ### Start debugging diff --git a/misc/README.md.erb b/misc/README.md.erb index d591a2f2b..75a05e3ff 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -509,6 +509,30 @@ The `<...>` notation means the argument. <%= DEBUGGER__.help %> +### Using IRB as the Debug Console + +Starting from version `v1.9`, you can now use IRB as the debug console. This integration brings additional features such as: + +* Autocompletion +* Support for multi-line input +* Access to commands not available in `debug`, like `show_source` or `show_doc` +* [Configurable command aliases](https://docs.ruby-lang.org/en/master/IRB.html#module-IRB-label-Command+Aliases) + +To switch to the IRB console, simply use the `irb` command in the debug console. + +Once activated, you'll notice the prompt changes to: + +```txt +irb:rdbg(main):001> +``` + +If you want to make IRB the default console for all sessions, configure the `irb_console` setting by either: + +* Setting the `RUBY_DEBUG_IRB_CONSOLE=true` environment variable +* Or adding `config set irb_console 1` to your `~/.rdbgrc` + +To disable the IRB console in the current session, execute `config set irb_console 0` in the console. + ## Debugger API ### Start debugging From 6407c98b808085b015c67f8665d7c4add5a642fe Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Wed, 20 Mar 2024 21:11:10 +0000 Subject: [PATCH 218/263] Format tables --- README.md | 16 ++++++++-------- misc/README.md.erb | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f6cf08010..c8f17c877 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ New debug.rb has several advantages: * TCP/IP * Integration with rich debugger frontends - Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | - ---|---|---|---| - Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | - Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | + | Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | + | ----------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------- | + | Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | + | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | * Extensible: application can introduce debugging support in several ways: * By `rdbg` command @@ -289,10 +289,10 @@ You can run your application as a remote debuggee, and the remote debugger conso There are multiple ways to run your program as a debuggee: -Stop at program start | [`rdbg` option](https://github.com/ruby/debug#rdbg---open-or-rdbg--o-for-short) | [require](https://github.com/ruby/debug#require-debugopen-in-a-program) | [debugger API](https://github.com/ruby/debug#start-by-method) ----|---|---|---| -Yes | `rdbg --open` | `require "debug/open"` | `DEBUGGER__.open` -No | `rdbg --open --nonstop` | `require "debug/open_nonstop"` | `DEBUGGER__.open(nonstop: true)` +| Stop at program start | [`rdbg` option](https://github.com/ruby/debug#rdbg---open-or-rdbg--o-for-short) | [require](https://github.com/ruby/debug#require-debugopen-in-a-program) | [debugger API](https://github.com/ruby/debug#start-by-method) | +| --------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------- | +| Yes | `rdbg --open` | `require "debug/open"` | `DEBUGGER__.open` | +| No | `rdbg --open --nonstop` | `require "debug/open_nonstop"` | `DEBUGGER__.open(nonstop: true)` | #### `rdbg --open` (or `rdbg -O` for short) diff --git a/misc/README.md.erb b/misc/README.md.erb index 75a05e3ff..e6751997b 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -13,10 +13,10 @@ New debug.rb has several advantages: * TCP/IP * Integration with rich debugger frontends - Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | - ---|---|---|---| - Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | - Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | + | Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | + | ----------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------- | + | Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | + | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | * Extensible: application can introduce debugging support in several ways: * By `rdbg` command @@ -289,10 +289,10 @@ You can run your application as a remote debuggee, and the remote debugger conso There are multiple ways to run your program as a debuggee: -Stop at program start | [`rdbg` option](https://github.com/ruby/debug#rdbg---open-or-rdbg--o-for-short) | [require](https://github.com/ruby/debug#require-debugopen-in-a-program) | [debugger API](https://github.com/ruby/debug#start-by-method) ----|---|---|---| -Yes | `rdbg --open` | `require "debug/open"` | `DEBUGGER__.open` -No | `rdbg --open --nonstop` | `require "debug/open_nonstop"` | `DEBUGGER__.open(nonstop: true)` +| Stop at program start | [`rdbg` option](https://github.com/ruby/debug#rdbg---open-or-rdbg--o-for-short) | [require](https://github.com/ruby/debug#require-debugopen-in-a-program) | [debugger API](https://github.com/ruby/debug#start-by-method) | +| --------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------- | +| Yes | `rdbg --open` | `require "debug/open"` | `DEBUGGER__.open` | +| No | `rdbg --open --nonstop` | `require "debug/open_nonstop"` | `DEBUGGER__.open(nonstop: true)` | #### `rdbg --open` (or `rdbg -O` for short) From 0b77e8294b5b220b3b2a089bf09f94808654899a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 29 Mar 2024 17:26:39 +0900 Subject: [PATCH 219/263] v1.9.2 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 6ccf565c8..cf7b7b23e 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.9.1" + VERSION = "1.9.2" end From 8abc50acba3d079aec8107c60ecae8a0285413ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nyikos=20Zolt=C3=A1n?= Date: Thu, 30 May 2024 16:17:16 +0200 Subject: [PATCH 220/263] do not include `$FILENAME` in globals `$FILENAME` is unsafe to include in the globals because it modifies ARGV and raises an error if it's a file that does not exist. This causes two issues if rdbg used to debug a command with arguments. * when using rdbg the server will crash when running `info globals`, as it does not catch the error * when using a DAP client that requests globals before the debugged program was able to handle its arguments then the ARGV changes and the program will not do what's expected --- lib/debug/thread_client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 80a434b0c..1d35d754a 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -44,7 +44,7 @@ def skip_location?(loc) end module GlobalVariablesHelper - SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze + SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE $FILENAME].freeze def safe_global_variables global_variables.reject{|name| SKIP_GLOBAL_LIST.include? name } end From 79cdcfa5bf693b655b1230773ac6fdda5fbf53ed Mon Sep 17 00:00:00 2001 From: tompng Date: Thu, 25 Jul 2024 02:02:55 +0900 Subject: [PATCH 221/263] Accept colon style Hash#inspect in test/console/print_test.rb Accepts {key=>value} style and {key: value} style Hash#inspect proposed in https://bugs.ruby-lang.org/issues/20433#note-10 --- test/console/print_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/console/print_test.rb b/test/console/print_test.rb index 3f9702b76..16f5c4436 100644 --- a/test/console/print_test.rb +++ b/test/console/print_test.rb @@ -15,7 +15,7 @@ def test_p_prints_the_expression debug_code(program) do type "c" type "p h" - assert_line_text('{:foo=>"bar"}') + assert_line_text({ foo: "bar" }.inspect) type "c" end end @@ -24,7 +24,7 @@ def test_pp_pretty_prints_the_expression debug_code(program) do type "c" type "pp h" - assert_line_text([/\{:foo=>/, /"bar"\}/]) + assert_line_text({ foo: "bar" }.pretty_print_inspect) type "c" end end From ef5e54cd75cb20b4085bdc77de9105a19af55a2e Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 2 Sep 2024 12:51:28 +0900 Subject: [PATCH 222/263] Fix flaky tests "1234" is too short and may be included in tempfile paths. --- test/console/catch_test.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/console/catch_test.rb b/test/console/catch_test.rb index 164ac4288..d4addf997 100644 --- a/test/console/catch_test.rb +++ b/test/console/catch_test.rb @@ -44,29 +44,29 @@ def test_catch_command_isnt_repeatable def test_catch_works_with_command debug_code(program) do - type 'catch ZeroDivisionError pre: p "1234"' + type 'catch ZeroDivisionError pre: p "catching zero division"' assert_line_text(/#0 BP - Catch "ZeroDivisionError"/) type 'continue' - assert_line_text(/1234/) + assert_line_text(/catching zero division/) type 'continue' type 'continue' end debug_code(program) do - type 'catch ZeroDivisionError do: p "1234"' + type 'catch ZeroDivisionError do: p "catching zero division"' assert_line_text(/#0 BP - Catch "ZeroDivisionError"/) type 'continue' - assert_line_text(/1234/) + assert_line_text(/catching zero division/) type 'continue' end end def test_catch_works_with_condition debug_code(program) do - type 'catch ZeroDivisionError if: a == 2 do: p "1234"' + type 'catch ZeroDivisionError if: a == 2 do: p "catching zero division"' assert_line_text(/#0 BP - Catch "ZeroDivisionError"/) type 'continue' - assert_no_line_text(/1234/) + assert_no_line_text(/catching zero division/) type 'continue' end end From 9c4279598e9e0376657b3813bf76a206f1f97beb Mon Sep 17 00:00:00 2001 From: fynsta <63241108+fynsta@users.noreply.github.com> Date: Tue, 10 Sep 2024 06:58:27 +0200 Subject: [PATCH 223/263] Add changelog_uri to gemspec (#1106) * Add changelog_uri to gemspec Supported here: https://guides.rubygems.org/specification-reference/#metadata Useful for running https://github.com/MaximeD/gem_updater * Remove wrong comma --- debug.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/debug.gemspec b/debug.gemspec index 2a5891f32..f77ae68ae 100644 --- a/debug.gemspec +++ b/debug.gemspec @@ -14,6 +14,7 @@ Gem::Specification.new do |spec| spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage + spec.metadata["changelog_uri"] = "#{spec.homepage}/releases/tag/v#{spec.version}" # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. From 1405bf86c04944a402e21edf547174e867592bdb Mon Sep 17 00:00:00 2001 From: Andrew H Schwartz Date: Fri, 10 May 2024 14:41:51 -0400 Subject: [PATCH 224/263] Fix minor typos / grammar in README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c8f17c877..b8a35386f 100644 --- a/README.md +++ b/README.md @@ -244,16 +244,16 @@ It will help if you want to know what the program is doing. If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. -* Without `-c` option, `rdbg ` means that `` is Ruby script and invoke it like `ruby ` with the debugger. -* With `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. +* Without the `-c` option, `rdbg ` means that `` is a Ruby script and invokes it like `ruby ` with the debugger. +* With the `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. Examples: * `rdbg -c -- rails server` * `rdbg -c -- bundle exec ruby foo.rb` * `rdbg -c -- bundle exec rake test` -* `rdbg -c -- ruby target.rb` is same as `rdbg target.rb` +* `rdbg -c -- ruby target.rb` is the same as `rdbg target.rb` -NOTE: `--` is needed to separate the command line options for `rdbg` and invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. +NOTE: `--` is needed to separate the command line options for `rdbg` and the invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`. From 07df517e3fc4324c268007362f290bf40f14af52 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 10 May 2024 21:38:51 -0400 Subject: [PATCH 225/263] Modify misc/README.md.erb and regenerate README --- misc/README.md.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/misc/README.md.erb b/misc/README.md.erb index e6751997b..678c9ddec 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -244,16 +244,16 @@ It will help if you want to know what the program is doing. If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. -* Without `-c` option, `rdbg ` means that `` is Ruby script and invoke it like `ruby ` with the debugger. -* With `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. +* Without the `-c` option, `rdbg ` means that `` is a Ruby script and invokes it like `ruby ` with the debugger. +* With the `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. Examples: * `rdbg -c -- rails server` * `rdbg -c -- bundle exec ruby foo.rb` * `rdbg -c -- bundle exec rake test` -* `rdbg -c -- ruby target.rb` is same as `rdbg target.rb` +* `rdbg -c -- ruby target.rb` is the same as `rdbg target.rb` -NOTE: `--` is needed to separate the command line options for `rdbg` and invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. +NOTE: `--` is needed to separate the command line options for `rdbg` and the invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`. From ee59c8565111a87ea1b1ac321c7d59c62b0f6337 Mon Sep 17 00:00:00 2001 From: tompng Date: Fri, 3 May 2024 13:23:12 +0900 Subject: [PATCH 226/263] Prompt assertion should use assert_raw_line_text instead of assert_line_text --- test/console/irb_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/console/irb_test.rb b/test/console/irb_test.rb index 857d02dfd..746f9acdb 100644 --- a/test/console/irb_test.rb +++ b/test/console/irb_test.rb @@ -47,7 +47,7 @@ def test_irb_command_switches_console_to_irb debug_code(program, remote: false) do type 'irb' type '123' - assert_line_text 'irb:rdbg(main):002> 123' + assert_raw_line_text 'irb:rdbg(main):002> 123' type 'irb_info' assert_line_text('IRB version:') type 'next' @@ -67,7 +67,7 @@ def test_irb_console_config_activates_irb debug_code(program, remote: false) do type '123' - assert_line_text 'irb:rdbg(main):002> 123' + assert_raw_line_text 'irb:rdbg(main):002> 123' type 'irb_info' assert_line_text('IRB version:') type 'next' From 36858594404a8f3eeb0d6f7335c6ff529d936582 Mon Sep 17 00:00:00 2001 From: Stan Lo Date: Thu, 11 Apr 2024 12:58:42 +0100 Subject: [PATCH 227/263] Improve RUBYOPT's handling in tests When debugging the issue related to https://github.com/ruby/irb/pull/919, I noticed that debugger tests don't respect the IRB version I specified in the Gemfile. This is because console tests force override the RUBYOPT env, which will remove the `-rbundler/setup` injected by bundler. Further more, if tests use `run_rdbg` with the `rubyopt` option, the RUBYOPT will be overridden yet again. So in this commit I did 2 improvements: 1. `run_rdbg` should append instead of override RUBYOPT 2. If tests are executed with bundler, we also run the debugger in PTY process with bundler by appending `-rbundler/setup` to RUBYOPT --- test/support/console_test_case.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/support/console_test_case.rb b/test/support/console_test_case.rb index f7e62fb4b..187506e99 100644 --- a/test/support/console_test_case.rb +++ b/test/support/console_test_case.rb @@ -225,7 +225,12 @@ def prepare_test_environment(program, test_steps, &block) @scenario = [] test_steps.call @scenario.freeze - inject_lib_to_load_path + + ENV['RUBYOPT'] = "-I #{__dir__}/../../lib" + + if ENV.key?('BUNDLE_GEMFILE') + ENV["RUBYOPT"] += " -rbundler/setup" + end block.call @@ -283,7 +288,7 @@ def run_rdbg program, options: nil, rubyopt: nil, &test_steps prepare_test_environment(program, test_steps) do test_info = TestInfo.new(dup_scenario, 'LOCAL', /\(rdbg\)/) cmd = "#{RDBG_EXECUTABLE} #{options} -- #{temp_file_path}" - cmd = "RUBYOPT=#{rubyopt} #{cmd}" if rubyopt + ENV["RUBYOPT"] += " #{rubyopt}" if rubyopt run_test_scenario cmd, test_info end end @@ -301,10 +306,6 @@ def new_thread &block end end - def inject_lib_to_load_path - ENV['RUBYOPT'] = "-I #{__dir__}/../../lib" - end - def assert_empty_queue test_info, exception: nil message = "Expected all commands/assertions to be executed. Still have #{test_info.queue.length} left." if exception From 87d607df7bff4666cf4fff9596551d96eb52f321 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 18 Dec 2024 06:07:57 +0900 Subject: [PATCH 228/263] allow `puts` without argument pointed out at https://github.com/ruby/debug/issues/1123 --- lib/debug/server_cdp.rb | 2 +- lib/debug/server_dap.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/server_cdp.rb b/lib/debug/server_cdp.rb index 3826f1242..9adb09795 100644 --- a/lib/debug/server_cdp.rb +++ b/lib/debug/server_cdp.rb @@ -688,7 +688,7 @@ def sock skip: false yield $stderr end - def puts result='' + def puts result = "" # STDERR.puts "puts: #{result}" # send_event 'output', category: 'stderr', output: "PUTS!!: " + result.to_s end diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 87c22ca45..7502182a4 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -501,7 +501,7 @@ def respond req, res send_response(req, **res) end - def puts result + def puts result = "" # STDERR.puts "puts: #{result}" send_event 'output', category: 'console', output: "#{result&.chomp}\n" end From affee18b44b38b1b50aedec4edbbba58e19143cd Mon Sep 17 00:00:00 2001 From: gerymate Date: Mon, 7 Oct 2024 18:29:31 +0200 Subject: [PATCH 229/263] Add option for trying a range of TCP ports --- README.md | 6 +++++- lib/debug/config.rb | 4 ++++ lib/debug/server.rb | 11 ++++++++++- misc/README.md.erb | 4 +++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b8a35386f..2cd3ddf51 100644 --- a/README.md +++ b/README.md @@ -330,7 +330,9 @@ When `rdbg --attach` connects to the debuggee, you can use any debug commands (s NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. -If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. +If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. You can add an optional `--port_range` option to try multiple ports in a reliable way. For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347, ... until it finds an available port. + +```shell To connect to the debuggee, you need to specify the port. @@ -499,6 +501,7 @@ config set no_color true * REMOTE * `RUBY_DEBUG_OPEN` (`open`): Open remote port (same as `rdbg --open` option) * `RUBY_DEBUG_PORT` (`port`): TCP/IP remote debugging: port + * `RUBY_DEBUG_PORT_RANGE` (`port_range`): TCP/IP remote debugging: length of port range * `RUBY_DEBUG_HOST` (`host`): TCP/IP remote debugging: host (default: 127.0.0.1) * `RUBY_DEBUG_SOCK_PATH` (`sock_path`): UNIX Domain Socket remote debugging: socket path * `RUBY_DEBUG_SOCK_DIR` (`sock_dir`): UNIX Domain Socket remote debugging: socket directory @@ -907,6 +910,7 @@ Debug console mode: Now rdbg, vscode and chrome is supported. --sock-path=SOCK_PATH UNIX Domain socket path --port=PORT Listening TCP/IP port + --port-range=PORT_RANGE Number of ports to try to connect to --host=HOST Listening TCP/IP host --cookie=COOKIE Set a cookie for connection --session-name=NAME Session name diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 86b9bfdc9..0fcbea7ec 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -44,6 +44,7 @@ module DEBUGGER__ # remote setting open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"], port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"], + port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"], host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"], sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"], sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"], @@ -352,6 +353,9 @@ def self.parse_argv argv o.on('--port=PORT', 'Listening TCP/IP port') do |port| config[:port] = port end + o.on('--port-range=PORT_RANGE', 'Number of ports to try to connect to') do |port_range| + config[:port_range] = port_range + end o.on('--host=HOST', 'Listening TCP/IP host') do |host| config[:host] = host end diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 0915b5bd5..562982296 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -399,6 +399,13 @@ def initialize host: nil, port: nil raise "Specify digits for port number" end end + @port_range = if @port.zero? + 0 + else + port_range_str = (port_range || CONFIG[:port_range] || "0").to_s + raise "Specify a positive integer <=16 for port range" unless port_range_str.match?(/\A\d+\z/) && port_range_str.to_i <= 16 + port_range_str.to_i + end @uuid = nil # for CDP super() @@ -452,7 +459,9 @@ def accept end end rescue Errno::EADDRINUSE - if retry_cnt < 10 + number_of_retries = @port_range.zero? ? 10 : @port_range + if retry_cnt < number_of_retries + @port += 1 unless @port_range.zero? retry_cnt += 1 sleep 0.1 retry diff --git a/misc/README.md.erb b/misc/README.md.erb index 678c9ddec..90bb57e17 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -330,7 +330,9 @@ When `rdbg --attach` connects to the debuggee, you can use any debug commands (s NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. -If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. +If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. You can add an optional `--port_range` option to try multiple ports in a reliable way. For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347, ... until it finds an available port. + +```shell To connect to the debuggee, you need to specify the port. From 51b0161194f2b50e4c5d13968871e3c2625c3d85 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 18 Dec 2024 10:48:40 +0900 Subject: [PATCH 230/263] `port_range` lvar is not defined --- lib/debug/server.rb | 2 +- test/support/test_case.rb | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 562982296..41f3bca13 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -402,7 +402,7 @@ def initialize host: nil, port: nil @port_range = if @port.zero? 0 else - port_range_str = (port_range || CONFIG[:port_range] || "0").to_s + port_range_str = (CONFIG[:port_range] || "0").to_s raise "Specify a positive integer <=16 for port range" unless port_range_str.match?(/\A\d+\z/) && port_range_str.to_i <= 16 port_range_str.to_i end diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 5ff8a2e27..2d1d26f96 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -180,6 +180,9 @@ def setup_remote_debuggee(cmd) msg1 = true when /\ADEBUGGER: wait for debugger connection/ msg2 = true + else + # unknown lines + STDERR.puts "> #{line}" end break if msg1 && msg2 From bead0984d241a91235e3d3bacd247f0363d2d530 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 19 Dec 2024 05:48:41 +0900 Subject: [PATCH 231/263] v1.10.0 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index cf7b7b23e..f1d1e9467 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.9.2" + VERSION = "1.10.0" end From ba7c39de085036f00862ea4878b77a2a46ff64bc Mon Sep 17 00:00:00 2001 From: Nony Dutton Date: Thu, 4 Apr 2024 20:11:45 +0200 Subject: [PATCH 232/263] Add `show_src_lines_frame` option Both `up` and `down` only show 1 source line when called, I think it would be more useful if there was a configurable way to provide more context. This adds a `show_src_lines_frame` configuration option (which defaults to `1`) that determines how many source lines get shown for frame operations `up`, `down`, and `set` (frame). --- README.md | 1 + lib/debug/config.rb | 73 ++++++++++++++++++------------------ lib/debug/thread_client.rb | 6 +-- test/console/config_test.rb | 75 +++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 2cd3ddf51..00ae01b9d 100644 --- a/README.md +++ b/README.md @@ -471,6 +471,7 @@ config set no_color true * UI * `RUBY_DEBUG_LOG_LEVEL` (`log_level`): Log level same as Logger (default: WARN) * `RUBY_DEBUG_SHOW_SRC_LINES` (`show_src_lines`): Show n lines source code on breakpoint (default: 10) + * `RUBY_DEBUG_SHOW_SRC_LINES_FRAME` (`show_src_lines_frame`): Show n lines source code on frame operations (default: 1) * `RUBY_DEBUG_SHOW_EVALEDSRC` (`show_evaledsrc`): Show actually evaluated source (default: false) * `RUBY_DEBUG_SHOW_FRAMES` (`show_frames`): Show n frames on breakpoint (default: 2) * `RUBY_DEBUG_USE_SHORT_PATH` (`use_short_path`): Show shorten PATH (like $(Gem)/foo.rb) (default: false) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 0fcbea7ec..b083a5ca3 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -12,50 +12,51 @@ module DEBUGGER__ CONFIG_SET = { # UI setting - log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"], - show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"], - show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"], - show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"], - use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"], - no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"], - no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"], - no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], - no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], - no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], - irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], + log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"], + show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"], + show_src_lines_frame:['RUBY_DEBUG_SHOW_SRC_LINES_FRAME', "UI: Show n lines source code on frame operations", :int, "1"], + show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"], + show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"], + use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"], + no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"], + no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"], + no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], + no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], + no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], + irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting - skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], - skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"], - keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"], - postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"], - fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"], - sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"], + skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], + skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"], + keep_alloc_site: ['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"], + postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"], + fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"], + sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"], # boot setting - nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"], - stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"], - init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], - commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], - no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], - history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"], - save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], + nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"], + stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"], + init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], + commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], + no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], + history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"], + save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], # remote setting - open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"], - port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"], - port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"], - host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"], - sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"], - sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"], - local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map], - skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'], - cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"], - session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"], - chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"], + open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"], + port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"], + port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"], + host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"], + sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"], + sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"], + local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map], + skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'], + cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"], + session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"], + chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"], # obsolete - parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"], + parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"], }.freeze CONFIG_MAP = CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 1d35d754a..259d69fcc 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1079,13 +1079,13 @@ def wait_next_action_ when :up if @current_frame_index + 1 < @target_frames.size @current_frame_index += 1 - show_src max_lines: 1 + show_src max_lines: CONFIG[:show_src_lines_frame] show_frame(@current_frame_index) end when :down if @current_frame_index > 0 @current_frame_index -= 1 - show_src max_lines: 1 + show_src max_lines: CONFIG[:show_src_lines_frame] show_frame(@current_frame_index) end when :set @@ -1097,7 +1097,7 @@ def wait_next_action_ puts "out of frame index: #{index}" end end - show_src max_lines: 1 + show_src max_lines: CONFIG[:show_src_lines_frame] show_frame(@current_frame_index) else raise "unsupported frame operation: #{arg.inspect}" diff --git a/test/console/config_test.rb b/test/console/config_test.rb index 589be7488..6d87b6da4 100644 --- a/test/console/config_test.rb +++ b/test/console/config_test.rb @@ -105,6 +105,81 @@ def test_show_src_lines_control_the_lines_displayed_on_breakpoint end end + class ShowSrcLinesFrameTest < ConsoleTestCase + def program + <<~RUBY + 1| class Foo + 2| def self.a + 3| p 1 + 4| p 2 + 5| p 3 + 6| p 3 + 7| p 5 + 8| p 6 + 9| p 7 + 10| p 8 + 11| p 9 + 12| p 10 + 13| b + 14| end + 15| + 16| def self.b + 17| binding.b + 18| p 11 + 19| end + 20| end + 21| + 22| Foo.a + RUBY + end + + def test_show_src_lines_control_the_lines_displayed_on_up + debug_code(program) do + type 'config set show_src_lines_frame 2' + type 'continue' + type 'up' + assert_line_text([ + /12\| p 10/, + /=> 13\| b/, + ]) + assert_no_line_text(/11\|/) + assert_no_line_text(/14\|/) + type 'continue' + end + end + + def test_show_src_lines_control_the_lines_displayed_on_down + debug_code(program) do + type 'config set show_src_lines_frame 2' + type 'continue' + type 'up' + type 'down' + assert_line_text([ + /16\| def self\.b/, + /=> 17\| binding\.b/ + ]) + assert_no_line_text(/15\|/) + assert_no_line_text(/18\|/) + type 'continue' + end + end + + def test_show_src_lines_control_the_lines_displayed_on_set + debug_code(program) do + type 'config set show_src_lines_frame 2' + type 'continue' + type 'frame' + assert_line_text([ + /16\| def self\.b/, + /=> 17\| binding\.b/ + ]) + assert_no_line_text(/15\|/) + assert_no_line_text(/18\|/) + type 'continue' + end + end + end + class ShowOrigSrcTest < ConsoleTestCase def program <<~RUBY From 69d245aedee01dc8eb64113f30e75d2a0ee91235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Diego=20Piske?= Date: Sat, 26 Apr 2025 18:44:01 -0300 Subject: [PATCH 233/263] Fix FrameInfo#block_identifier Since ruby 3.4, not all cases match BLOCK_LABL_REGEXP anymore This fixes for those cases. --- lib/debug/frame_info.rb | 4 +- test/console/frame_block_identifier_test.rb | 58 +++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/console/frame_block_identifier_test.rb diff --git a/lib/debug/frame_info.rb b/lib/debug/frame_info.rb index 8eb041969..8fab332de 100644 --- a/lib/debug/frame_info.rb +++ b/lib/debug/frame_info.rb @@ -86,7 +86,9 @@ def frame_type def block_identifier return unless frame_type == :block - _, level, block_loc = location.label.match(BLOCK_LABL_REGEXP).to_a + re_match = location.label.match(BLOCK_LABL_REGEXP) + _, level, block_loc = re_match ? re_match.to_a : [nil, nil, location.label] + [level || "", block_loc] end diff --git a/test/console/frame_block_identifier_test.rb b/test/console/frame_block_identifier_test.rb new file mode 100644 index 000000000..a4349da19 --- /dev/null +++ b/test/console/frame_block_identifier_test.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require_relative '../support/console_test_case' + +module DEBUGGER__ + + class FrameBlockIdentifierTest < ConsoleTestCase + def program + <<~RUBY + 1| + 2| class Whatever + 3| def some_method + 4| will_exit = false + 5| loop do + 6| return if will_exit + 7| will_exit = true + 8| + 9| begin + 10| raise "foo" + 11| rescue => e + 12| puts "the end" + 13| end + 14| end + 15| end + 16| end + 17| + 18| Whatever.new.some_method + RUBY + end + + def test_frame_block_identifier + debug_code(program) do + type 'b 12' + type 'c' + assert_line_num 12 + assert_line_text([ + /\[7, 16\] in .*/, + / 7\| will_exit = true/, + / 8\| /, + / 9\| begin/, + / 10\| raise "foo"/, + / 11\| rescue => e/, + /=> 12\| puts "the end"/, + / 13\| end/, + / 14\| end/, + / 15\| end/, + / 16\| end/, + /=>\#0\tWhatever\#some_method at .*/, + / \#1\tblock in Kernel\#loop at :168/, + / \# and 2 frames \(use `bt' command for all frames\)/, + //, + /Stop by \#0 BP \- Line .*/ + ]) + type 'c' + end + end + end +end From a9bbc701feb87c1e28404292338d3c75cc49a87e Mon Sep 17 00:00:00 2001 From: Steven Harman Date: Fri, 11 Apr 2025 11:22:22 -0400 Subject: [PATCH 234/263] =?UTF-8?q?Normalize=20formatting,=20grammar,=20et?= =?UTF-8?q?c=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just that - normalizing various formatting, code blocks, fixing some grammar and typos, and the like. --- README.md | 208 +++++++++++++++++++++++++-------------------- misc/README.md.erb | 208 +++++++++++++++++++++++++-------------------- 2 files changed, 232 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index 00ae01b9d..412c6d652 100644 --- a/README.md +++ b/README.md @@ -16,38 +16,38 @@ New debug.rb has several advantages: | Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | | ----------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------- | | Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | - | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | + | Requirement | None | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | * Extensible: application can introduce debugging support in several ways: * By `rdbg` command * By loading libraries with `-r` command line option * By calling Ruby's method explicitly * Misc - * Support threads (almost done) and ractors (TODO). - * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing. + * Support threads (almost done) and Ractors (TODO). + * Support suspending and entering the debug console with `Ctrl-C` at most of timing. * Show parameters on backtrace command. - * Support recording & replay debugging. + * Support recording and replay debugging. # Installation -``` +```console $ gem install debug ``` -or specify `-Ipath/to/debug/lib` in `RUBYOPT` or each ruby command-line option, especially for debug this gem development. +Alternatively, specify `-Ipath/to/debug/lib` in `RUBYOPT`, or as a Ruby command-line option +This is especially useful for debugging this gem during development. -If you use Bundler, write the following line to your Gemfile. +If using Bundler, add the following to your Gemfile: -``` +```ruby gem "debug", ">= 1.0.0" ``` -(The version constraint is important; `debug < 1.0.0` is an older, -abandoned gem that is completely different from this product.) +(The version constraint is important; `debug < 1.0.0` is an older, abandoned gem that is completely different from this product.) # HOW TO USE -To use a debugger, roughly you will do the following steps: +To use the debugger, you will do roughly the following steps: 1. Set breakpoints. 2. Run a program with the debugger. @@ -63,22 +63,23 @@ To use a debugger, roughly you will do the following steps: ## Invoke with the debugger -There are several options for (1) and (2). Please choose your favorite way. +There are several ways to invoke the debugger, depending on your needs, preferences, and the environment. ### Modify source code with [`binding.break`](#bindingbreak-method) (similar to `binding.pry` or `binding.irb`) -If you can modify the source code, you can use the debugger by adding `require 'debug'` at the top of your program and putting [`binding.break`](#bindingbreak-method) method into lines where you want to stop as breakpoints like `binding.pry` and `binding.irb`. +If you can modify the source code, you can use the debugger by adding `require 'debug'` at the top of your program and putting [`binding.break`](#bindingbreak-method) method into lines where you want to stop as breakpoints. +This is similar to how `binding.pry` and `binding.irb` work. -You can also use its 2 aliases in the same way: +`binding.break` has two aliases which do the same thing: - `binding.b` - `debugger` After that, run the program as usual and you will enter the debug console at breakpoints you inserted. -The following example shows the demonstration of [`binding.break`](#bindingbreak-method). +The following is an example of the [`binding.break`](#bindingbreak-method) method. -```shell +```console $ cat target.rb # Sample program require 'debug' @@ -140,10 +141,11 @@ d => 4 ### Invoke the program from the debugger as a traditional debuggers -If you don't want to modify the source code, you can set breakpoints with a debug command `break` (`b` for short). -Using `rdbg` command (or `bundle exec rdbg`) to launch the program without any modifications, you can run the program with the debugger. +If you don't want to modify the source code, you can use the `rdbg` command (or `bundle exec rdbg`) to run the program with the debugger. +This is similar to how you'd launch a program with `ruby program.rb`. +Then you can set breakpoints with the debug command `break` (`b` for short). -```shell +```console $ cat target.rb # Sample program a = 1 b = 2 @@ -166,9 +168,11 @@ DEBUGGER: Session start (pid: 7656) (rdbg) ``` -`rdbg` command suspends the program at the beginning of the given script (`target.rb` in this case) and you can use debug commands. `(rdbg)` is prompt. Let's set breakpoints on line 3 and line 5 with `break` command (`b` for short). +The `rdbg` command suspends the program at the beginning of the given script (`target.rb` in this case) and you can use debug commands to control execution from there. +`(rdbg)` is the console prompt. +Let's set breakpoints on line 3 and line 5 with `break` command (`b` for short). -```shell +```console (rdbg) break 3 # set breakpoint at line 3 #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) @@ -180,9 +184,10 @@ DEBUGGER: Session start (pid: 7656) #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line) ``` -You can see that two breakpoints are registered. Let's continue the program by using the `continue` command. +You can see that two breakpoints are registered. +Let's continue the program by using the `continue` command. -```shell +```console (rdbg) continue [1, 7] in target.rb 1| a = 1 @@ -199,11 +204,11 @@ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) (rdbg) ``` -You can see that we can stop at line 3. -Let's see the local variables with the `info` command, and continue. -You can also confirm that the program will suspend at line 5 and you can use the `info` command again. +You can see that we stopped at line 3. +Let's see the local variables with the `info` command, and continue execution with the `continue`. +The program will then suspend at line 5 and you can use the `info` command again. -```shell +```console (rdbg) info =>#0
at target.rb:3 %self => main @@ -237,25 +242,28 @@ d => 4 [1, 2, 3, 4] ``` -By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console. +NOTE: When using `rdbg` you can suspend your application with `C-c` (SIGINT) and enter the debug console. It will help if you want to know what the program is doing. ### Use `rdbg` with commands written in Ruby -If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. +If you want to run an executable written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. -* Without the `-c` option, `rdbg ` means that `` is a Ruby script and invokes it like `ruby ` with the debugger. -* With the `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. +* Without the `-c` option, `rdbg ` means that `` is a Ruby script and it is invoked like `ruby ` with the debugger. +* With the `-c` option, `rdbg -c ` means that `` is an executable in `PATH` and simply invokes it with the debugger. Examples: + * `rdbg -c -- rails server` * `rdbg -c -- bundle exec ruby foo.rb` * `rdbg -c -- bundle exec rake test` * `rdbg -c -- ruby target.rb` is the same as `rdbg target.rb` -NOTE: `--` is needed to separate the command line options for `rdbg` and the invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. +NOTE: `--` is needed to separate the command line options for `rdbg` from the executable being invoked, and its options. +For example, `rdbg -c rake -T` would be parsed as `rdbg -c -T -- rake`, which is incorrect. +It should be `rdbg -c -- rake -T`. -NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`. +NOTE: If you want to use Bundler (`bundle` executable), you need to add `gem 'debug'` to your `Gemfile`. ### Using VSCode @@ -275,12 +283,13 @@ Please see the extension page for more details. ## Remote debugging -You can use this debugger as a remote debugger. For example, it will help in the following situations: +You can use this debugger as a remote debugger. +For example, it will help in the following situations: * Your application does not run on TTY, and it is hard to use `binding.pry` or `binding.irb`. * Your application is running on a Docker container, and there is no TTY. * Your application is running as a daemon. - * Your application uses pipe for STDIN or STDOUT. + * Your application uses pipe for `STDIN` or `STDOUT`. * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on). You can run your application as a remote debuggee, and the remote debugger console can attach to the debuggee anytime. @@ -296,10 +305,11 @@ There are multiple ways to run your program as a debuggee: #### `rdbg --open` (or `rdbg -O` for short) -You can run a script with `rdbg --open target.rb` command and run a `target.rb` as a debuggee program. It also opens the network port and suspends at the beginning of `target.rb`. +Launch a script with `rdbg --open target.rb` to run `target.rb` as a debuggee program. +It also opens the network port and suspends at the beginning of `target.rb`. -```shell -$ exe/rdbg --open target.rb +```console +$ rdbg --open target.rb DEBUGGER: Session start (pid: 7773) DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773) DEBUGGER: wait for debugger connection... @@ -309,7 +319,7 @@ By default, `rdbg --open` uses UNIX domain socket and generates the path name au You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short). -```shell +```console $ rdbg -A [1, 7] in target.rb => 1| a = 1 @@ -324,37 +334,41 @@ $ rdbg -A (rdbg:remote) ``` -If there are no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. +If there are no other files in the default directory, `rdbg --attach` will automatically connect to the UNIX domain socket listed. +If there are multiple files, you need to specify which to use. -When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate. +When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. +When a debuggee program exits, the remote console will also terminate. -NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. +NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). +If you want to exit the debuggee program, use `kill` command. -If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. You can add an optional `--port_range` option to try multiple ports in a reliable way. For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347, ... until it finds an available port. - -```shell +If you want to use TCP/IP for remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. +You can add an optional `--port_range` to try multiple ports in a reliable way. +For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347,… until it finds an available port. To connect to the debuggee, you need to specify the port. -```shell +```console $ rdbg --attach 12345 ``` If you want to choose the host to bind, you can use `--host` option. -Note that all messages communicated between the debugger and the debuggee are *NOT* encrypted so please use remote debugging carefully. +Messages communicated between the debugger and the debuggee are *NOT* encrypted so please use remote debugging carefully. #### `require 'debug/open'` in a program -If you can modify the program, you can open the debugging port by adding `require 'debug/open'` line in the program. +If you can modify the program, you can open the debugging port by adding `require 'debug/open'` in the program. If you don't want to stop the program at the beginning, you can also use `require 'debug/open_nonstop'`. Using `debug/open_nonstop` is useful if you want to open a backdoor to the application. However, it is also dangerous because it can become another vulnerability. Please use it carefully. -By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. +By default, UNIX domain socket is used for the debugging port. +To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. -```shell +```console $ RUBY_DEBUG_PORT=12345 ruby target.rb ``` @@ -366,9 +380,7 @@ You can attach with external debugger frontend with VSCode and Chrome. $ rdbg --open=[frontend] target.rb ``` -will open a debug port and `[frontend]` can attach to the port. - -Also `open` command allows opening the debug port. +This will open a debug port and the `[frontend]` can attach to the port. #### VSCode integration @@ -376,9 +388,9 @@ Also `open` command allows opening the debug port. If you don't run a debuggee Ruby process on VSCode, you can attach it to VSCode later with the following steps. -`rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command). +`rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` executable). -``` +```console $ rdbg --open=vscode target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-27706) DEBUGGER: wait for debugger connection... @@ -386,11 +398,11 @@ Launching: code /tmp/ruby-debug-vscode-20211014-27706-gd7e85/ /tmp/ruby-debug-vs DEBUGGER: Connected. ``` -And it tries to invoke the new VSCode window and VSCode starts attaching to the debuggee Ruby program automatically. +It tries to invoke the new VSCode window and VSCode will attach to the debuggee Ruby program automatically. -You can also use `open vscode` command in REPL. +You can also use `open vscode` in a REPL. -``` +```console $ rdbg target.rb [1, 8] in target.rb 1| @@ -409,9 +421,9 @@ Launching: code /tmp/ruby-debug-vscode-20211014-28337-kg9dm/ /tmp/ruby-debug-vsc DEBUGGER: Connected. ``` -If the machine which runs the Ruby process doesn't have a `code` command, the following message will be shown: +If the machine which runs the Ruby process doesn't have a `code` executable on `$PATH`, the following message will be shown: -``` +```console (rdbg) open vscode DEBUGGER: wait for debugger connection... DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-455) @@ -427,15 +439,13 @@ If your application is running on a SSH remote host, please try: ``` -and try to use the proposed commands. - Note that you can attach with `rdbg --attach` and continue REPL debugging. #### Chrome DevTool integration -With `rdbg --open=chrome` command will show the following message. +Using `rdbg --open=chrome` will show the following message: -``` +```console $ rdbg target.rb --open=chrome DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:43633) DEBUGGER: With Chrome browser, type the following URL in the address-bar: @@ -445,20 +455,25 @@ DEBUGGER: With Chrome browser, type the following URL in the address-bar: DEBUGGER: wait for debugger connection... ``` -Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address bar on Chrome browser, and you can continue the debugging with chrome browser. +Type the following in the address bar on Chrome browser, and you can continue the debugging with chrome browser: + +```txt +devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` +``` -Also `open chrome` command works like `open vscode`. +Similar to VSCode, you can use `open chrome` to open the debugger in Chrome. -For more information about how to use Chrome debugging, you might want to read [here](https://developer.chrome.com/docs/devtools/). +For more information about how to use Chrome debugging, [see the devtools docs](https://developer.chrome.com/docs/devtools/). ## Configuration You can configure the debugger's behavior with debug commands and environment variables. -When the debug session is started, initial scripts are loaded so you can put your favorite configurations in the initial scripts. +When the debug session is started, some [initialization scripts](#initial-scripts) (e.g., `~/.rdbgrc`) are loaded, allowing you to configure the debugger's behavior to your needs and preferences. ### Configuration list -You can configure the debugger's behavior with environment variables and `config` command. Each configuration has an environment variable and a name which can be specified by `config` command. +You can configure the debugger's behavior with environment variables and `config` command. +Each configuration has an environment variable and a name which can be specified by `config` command. ``` # configuration example @@ -525,7 +540,7 @@ There are other environment variables: ### Initial scripts -If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains debug commands) when the debug session is started. +If there is a `~/.rdbgrc` file it is loaded as an initialization script (which contains debug commands) when the debug session is started. * `RUBY_DEBUG_INIT_SCRIPT` environment variable can specify the initial script file. * You can specify the initial script with `rdbg -x initial_script` (like gdb's `-x` option). @@ -533,7 +548,7 @@ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains Initial scripts are useful to write your favorite configurations. For example, you can set breakpoints with `break file:123` in `~/.rdbgrc`. -If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing. +If there is a `~/.rdbgrc.rb` file it is also loaded as a Ruby script when the debug session is started. ## Debug command on the debug console @@ -542,16 +557,19 @@ On the debug console, you can use the following debug commands. There are additional features: * `` without debug command is almost the same as `pp `. - * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. So that the input `foo.bar` is the same as `pp foo.bar`. - * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. - * So the author (Koichi Sasada) recommends using `p`, `pp` or `eval` command to evaluate the Ruby expression every time. + * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. + So that the input `foo.bar` is the same as `pp foo.bar`. + * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. + For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. + * For consistency, the author (Koichi Sasada) recommends using the `p`, `pp`, or `eval` command to evaluate the Ruby expression every time. * `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands. * `Ctrl-D` is equal to `quit` command. * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing) -You can use the following debug commands. Each command should be written in 1 line. -The `[...]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. -The `<...>` notation means the argument. +You can use the following debug commands. +Each command should be written in 1 line. +The `[…]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. +The `<…>` notation means the argument. ### Control flow @@ -801,7 +819,7 @@ To switch to the IRB console, simply use the `irb` command in the debug console. Once activated, you'll notice the prompt changes to: -```txt +```console irb:rdbg(main):001> ``` @@ -828,9 +846,12 @@ You can start debugging without `rdbg` command by requiring the following librar You need to require one of them at the very beginning of the application. Using `ruby -r` (for example `ruby -r debug/start target.rb`) is another way to invoke with debugger. -NOTE: Until Ruby 3.0, there is old `lib/debug.rb` standard library. So that if this gem is not installed, or if `Gemfile` missed to list this gem and `bundle exec` is used, you will see the following output: +NOTE: Until Ruby 3.0, there is old `lib/debug.rb` in the standard library. +`lib/debug.rb` was not maintained well in recent years, and the purpose of this library is to rewrite old `lib/debug.rb` with recent techniques. + +So, if this gem is not installed, or if the `Gemfile` doesn't include this gem and `bundle exec` is used, you will see the following output: -```shell +```console $ ruby -r debug -e0 .../2.7.3/lib/ruby/2.7.0/x86_64-linux/continuation.so: warning: callcc is obsolete; use Fiber instead Debug.rb @@ -840,16 +861,15 @@ Emacs support available. (rdb:1) ``` -`lib/debug.rb` was not maintained well in recent years, and the purpose of this library is to rewrite old `lib/debug.rb` with recent techniques. - #### Start by method -After loading `debug/session`, you can start a debug session with the following methods. They are convenient if you want to specify debug configurations in your program. +After loading `debug/session`, you can start a debug session with the following methods. +They are convenient if you want to specify debug configurations in your program. * `DEBUGGER__.start(**kw)`: start debug session with local console. -* `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket) -* `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket -* `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP +* `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket). +* `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket. +* `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP. For example: @@ -863,24 +883,28 @@ DEBUGGER__.start(no_color: true, # disable colorize ### `binding.break` method -`binding.break` (or `binding.b`) set breakpoints at the written line. It also has several keywords. +`binding.break` (or `binding.b`) sets a breakpoint at that line. +It also has several keywords. If `do: 'command'` is specified, the debugger suspends the program, runs the `command` as a debug command, and continues the program. It is useful if you only want to call a debug command and don't want to stop there. +For example: -``` +```ruby def initialize @a = 1 binding.b do: 'info \n watch @a' end ``` -In this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. +In this case, execute the `info` command, then register a watch breakpoint for `@a` and continue to run. +You can also use `;;` instead of `\n` to separate your commands. If `pre: 'command'` is specified, the debugger suspends the program and runs the `command` as a debug command, and keeps suspended. It is useful if you have operations before suspend. +For example: -``` +```ruby def foo binding.b pre: 'p bar()' ... @@ -891,7 +915,7 @@ In this case, you can see the result of `bar()` every time you stop there. ## rdbg command help -``` +```console exe/rdbg [options] -- [debuggee options] Debug console mode: @@ -960,7 +984,7 @@ NOTE # Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug. +Bug reports and pull requests are welcome on GitHub at [https://github.com/ruby/debug](). This debugger is not mature so your feedback will help us. Please also check the [contributing guideline](/CONTRIBUTING.md). diff --git a/misc/README.md.erb b/misc/README.md.erb index 90bb57e17..9565a74da 100644 --- a/misc/README.md.erb +++ b/misc/README.md.erb @@ -16,38 +16,38 @@ New debug.rb has several advantages: | Frontend | [Console](https://github.com/ruby/debug#invoke-as-a-remote-debuggee) | [VSCode](https://github.com/ruby/debug#vscode-integration) | [Chrome DevTool](#chrome-devtool-integration) | | ----------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------- | | Connection | UDS, TCP/IP | UDS, TCP/IP | TCP/IP | - | Requirement | No | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | + | Requirement | None | [vscode-rdbg](https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg) | Chrome | * Extensible: application can introduce debugging support in several ways: * By `rdbg` command * By loading libraries with `-r` command line option * By calling Ruby's method explicitly * Misc - * Support threads (almost done) and ractors (TODO). - * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing. + * Support threads (almost done) and Ractors (TODO). + * Support suspending and entering the debug console with `Ctrl-C` at most of timing. * Show parameters on backtrace command. - * Support recording & replay debugging. + * Support recording and replay debugging. # Installation -``` +```console $ gem install debug ``` -or specify `-Ipath/to/debug/lib` in `RUBYOPT` or each ruby command-line option, especially for debug this gem development. +Alternatively, specify `-Ipath/to/debug/lib` in `RUBYOPT`, or as a Ruby command-line option +This is especially useful for debugging this gem during development. -If you use Bundler, write the following line to your Gemfile. +If using Bundler, add the following to your Gemfile: -``` +```ruby gem "debug", ">= 1.0.0" ``` -(The version constraint is important; `debug < 1.0.0` is an older, -abandoned gem that is completely different from this product.) +(The version constraint is important; `debug < 1.0.0` is an older, abandoned gem that is completely different from this product.) # HOW TO USE -To use a debugger, roughly you will do the following steps: +To use the debugger, you will do roughly the following steps: 1. Set breakpoints. 2. Run a program with the debugger. @@ -63,22 +63,23 @@ To use a debugger, roughly you will do the following steps: ## Invoke with the debugger -There are several options for (1) and (2). Please choose your favorite way. +There are several ways to invoke the debugger, depending on your needs, preferences, and the environment. ### Modify source code with [`binding.break`](#bindingbreak-method) (similar to `binding.pry` or `binding.irb`) -If you can modify the source code, you can use the debugger by adding `require 'debug'` at the top of your program and putting [`binding.break`](#bindingbreak-method) method into lines where you want to stop as breakpoints like `binding.pry` and `binding.irb`. +If you can modify the source code, you can use the debugger by adding `require 'debug'` at the top of your program and putting [`binding.break`](#bindingbreak-method) method into lines where you want to stop as breakpoints. +This is similar to how `binding.pry` and `binding.irb` work. -You can also use its 2 aliases in the same way: +`binding.break` has two aliases which do the same thing: - `binding.b` - `debugger` After that, run the program as usual and you will enter the debug console at breakpoints you inserted. -The following example shows the demonstration of [`binding.break`](#bindingbreak-method). +The following is an example of the [`binding.break`](#bindingbreak-method) method. -```shell +```console $ cat target.rb # Sample program require 'debug' @@ -140,10 +141,11 @@ d => 4 ### Invoke the program from the debugger as a traditional debuggers -If you don't want to modify the source code, you can set breakpoints with a debug command `break` (`b` for short). -Using `rdbg` command (or `bundle exec rdbg`) to launch the program without any modifications, you can run the program with the debugger. +If you don't want to modify the source code, you can use the `rdbg` command (or `bundle exec rdbg`) to run the program with the debugger. +This is similar to how you'd launch a program with `ruby program.rb`. +Then you can set breakpoints with the debug command `break` (`b` for short). -```shell +```console $ cat target.rb # Sample program a = 1 b = 2 @@ -166,9 +168,11 @@ DEBUGGER: Session start (pid: 7656) (rdbg) ``` -`rdbg` command suspends the program at the beginning of the given script (`target.rb` in this case) and you can use debug commands. `(rdbg)` is prompt. Let's set breakpoints on line 3 and line 5 with `break` command (`b` for short). +The `rdbg` command suspends the program at the beginning of the given script (`target.rb` in this case) and you can use debug commands to control execution from there. +`(rdbg)` is the console prompt. +Let's set breakpoints on line 3 and line 5 with `break` command (`b` for short). -```shell +```console (rdbg) break 3 # set breakpoint at line 3 #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) @@ -180,9 +184,10 @@ DEBUGGER: Session start (pid: 7656) #1 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:5 (line) ``` -You can see that two breakpoints are registered. Let's continue the program by using the `continue` command. +You can see that two breakpoints are registered. +Let's continue the program by using the `continue` command. -```shell +```console (rdbg) continue [1, 7] in target.rb 1| a = 1 @@ -199,11 +204,11 @@ Stop by #0 BP - Line /mnt/c/ko1/src/rb/ruby-debug/target.rb:3 (line) (rdbg) ``` -You can see that we can stop at line 3. -Let's see the local variables with the `info` command, and continue. -You can also confirm that the program will suspend at line 5 and you can use the `info` command again. +You can see that we stopped at line 3. +Let's see the local variables with the `info` command, and continue execution with the `continue`. +The program will then suspend at line 5 and you can use the `info` command again. -```shell +```console (rdbg) info =>#0
at target.rb:3 %self => main @@ -237,25 +242,28 @@ d => 4 [1, 2, 3, 4] ``` -By the way, using `rdbg` command you can suspend your application with `C-c` (SIGINT) and enter the debug console. +NOTE: When using `rdbg` you can suspend your application with `C-c` (SIGINT) and enter the debug console. It will help if you want to know what the program is doing. ### Use `rdbg` with commands written in Ruby -If you want to run a command written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. +If you want to run an executable written in Ruby like `rake`, `rails`, `bundle`, `rspec`, and so on, you can use `rdbg -c` option. -* Without the `-c` option, `rdbg ` means that `` is a Ruby script and invokes it like `ruby ` with the debugger. -* With the `-c` option, `rdbg -c ` means that `` is a command in `PATH` and simply invokes it with the debugger. +* Without the `-c` option, `rdbg ` means that `` is a Ruby script and it is invoked like `ruby ` with the debugger. +* With the `-c` option, `rdbg -c ` means that `` is an executable in `PATH` and simply invokes it with the debugger. Examples: + * `rdbg -c -- rails server` * `rdbg -c -- bundle exec ruby foo.rb` * `rdbg -c -- bundle exec rake test` * `rdbg -c -- ruby target.rb` is the same as `rdbg target.rb` -NOTE: `--` is needed to separate the command line options for `rdbg` and the invoking command. For example, `rdbg -c rake -T` is recognized like `rdbg -c -T -- rake`. It should be `rdbg -c -- rake -T`. +NOTE: `--` is needed to separate the command line options for `rdbg` from the executable being invoked, and its options. +For example, `rdbg -c rake -T` would be parsed as `rdbg -c -T -- rake`, which is incorrect. +It should be `rdbg -c -- rake -T`. -NOTE: If you want to use bundler (`bundle` command), you need to write `gem debug` line in your `Gemfile`. +NOTE: If you want to use Bundler (`bundle` executable), you need to add `gem 'debug'` to your `Gemfile`. ### Using VSCode @@ -275,12 +283,13 @@ Please see the extension page for more details. ## Remote debugging -You can use this debugger as a remote debugger. For example, it will help in the following situations: +You can use this debugger as a remote debugger. +For example, it will help in the following situations: * Your application does not run on TTY, and it is hard to use `binding.pry` or `binding.irb`. * Your application is running on a Docker container, and there is no TTY. * Your application is running as a daemon. - * Your application uses pipe for STDIN or STDOUT. + * Your application uses pipe for `STDIN` or `STDOUT`. * Your application is running as a daemon and you want to query the running status (checking a backtrace and so on). You can run your application as a remote debuggee, and the remote debugger console can attach to the debuggee anytime. @@ -296,10 +305,11 @@ There are multiple ways to run your program as a debuggee: #### `rdbg --open` (or `rdbg -O` for short) -You can run a script with `rdbg --open target.rb` command and run a `target.rb` as a debuggee program. It also opens the network port and suspends at the beginning of `target.rb`. +Launch a script with `rdbg --open target.rb` to run `target.rb` as a debuggee program. +It also opens the network port and suspends at the beginning of `target.rb`. -```shell -$ exe/rdbg --open target.rb +```console +$ rdbg --open target.rb DEBUGGER: Session start (pid: 7773) DEBUGGER: Debugger can attach via UNIX domain socket (/home/ko1/.ruby-debug-sock/ruby-debug-ko1-7773) DEBUGGER: wait for debugger connection... @@ -309,7 +319,7 @@ By default, `rdbg --open` uses UNIX domain socket and generates the path name au You can connect to the debuggee with `rdbg --attach` command (`rdbg -A` for short). -```shell +```console $ rdbg -A [1, 7] in target.rb => 1| a = 1 @@ -324,37 +334,41 @@ $ rdbg -A (rdbg:remote) ``` -If there are no other opening ports on the default directory, `rdbg --attach` command chooses the only one opening UNIX domain socket and connects to it. If there are more files, you need to specify the file. +If there are no other files in the default directory, `rdbg --attach` will automatically connect to the UNIX domain socket listed. +If there are multiple files, you need to specify which to use. -When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. When a debuggee program exits, the remote console will also terminate. +When `rdbg --attach` connects to the debuggee, you can use any debug commands (set breakpoints, continue the program, and so on) like the local debug console. +When a debuggee program exits, the remote console will also terminate. -NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). If you want to exit the debuggee program, use `kill` command. +NOTE: If you use the `quit` command, only the remote console exits and the debuggee program continues to run (and you can connect it again). +If you want to exit the debuggee program, use `kill` command. -If you want to use TCP/IP for the remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. You can add an optional `--port_range` option to try multiple ports in a reliable way. For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347, ... until it finds an available port. - -```shell +If you want to use TCP/IP for remote debugging, you need to specify the port and host with `--port` like `rdbg --open --port 12345` and it binds to `localhost:12345`. +You can add an optional `--port_range` to try multiple ports in a reliable way. +For example, `rdbg --open --port 12345 --port_range 10` will try to bind to 12345, 12346, 12347,… until it finds an available port. To connect to the debuggee, you need to specify the port. -```shell +```console $ rdbg --attach 12345 ``` If you want to choose the host to bind, you can use `--host` option. -Note that all messages communicated between the debugger and the debuggee are *NOT* encrypted so please use remote debugging carefully. +Messages communicated between the debugger and the debuggee are *NOT* encrypted so please use remote debugging carefully. #### `require 'debug/open'` in a program -If you can modify the program, you can open the debugging port by adding `require 'debug/open'` line in the program. +If you can modify the program, you can open the debugging port by adding `require 'debug/open'` in the program. If you don't want to stop the program at the beginning, you can also use `require 'debug/open_nonstop'`. Using `debug/open_nonstop` is useful if you want to open a backdoor to the application. However, it is also dangerous because it can become another vulnerability. Please use it carefully. -By default, UNIX domain socket is used for the debugging port. To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. +By default, UNIX domain socket is used for the debugging port. +To use TCP/IP, you can set the `RUBY_DEBUG_PORT` environment variable. -```shell +```console $ RUBY_DEBUG_PORT=12345 ruby target.rb ``` @@ -366,9 +380,7 @@ You can attach with external debugger frontend with VSCode and Chrome. $ rdbg --open=[frontend] target.rb ``` -will open a debug port and `[frontend]` can attach to the port. - -Also `open` command allows opening the debug port. +This will open a debug port and the `[frontend]` can attach to the port. #### VSCode integration @@ -376,9 +388,9 @@ Also `open` command allows opening the debug port. If you don't run a debuggee Ruby process on VSCode, you can attach it to VSCode later with the following steps. -`rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` command). +`rdbg --open=vscode` opens the debug port and tries to invoke the VSCode (`code` executable). -``` +```console $ rdbg --open=vscode target.rb DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-27706) DEBUGGER: wait for debugger connection... @@ -386,11 +398,11 @@ Launching: code /tmp/ruby-debug-vscode-20211014-27706-gd7e85/ /tmp/ruby-debug-vs DEBUGGER: Connected. ``` -And it tries to invoke the new VSCode window and VSCode starts attaching to the debuggee Ruby program automatically. +It tries to invoke the new VSCode window and VSCode will attach to the debuggee Ruby program automatically. -You can also use `open vscode` command in REPL. +You can also use `open vscode` in a REPL. -``` +```console $ rdbg target.rb [1, 8] in target.rb 1| @@ -409,9 +421,9 @@ Launching: code /tmp/ruby-debug-vscode-20211014-28337-kg9dm/ /tmp/ruby-debug-vsc DEBUGGER: Connected. ``` -If the machine which runs the Ruby process doesn't have a `code` command, the following message will be shown: +If the machine which runs the Ruby process doesn't have a `code` executable on `$PATH`, the following message will be shown: -``` +```console (rdbg) open vscode DEBUGGER: wait for debugger connection... DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/ruby-debug-sock-1000/ruby-debug-ko1-455) @@ -427,15 +439,13 @@ If your application is running on a SSH remote host, please try: ``` -and try to use the proposed commands. - Note that you can attach with `rdbg --attach` and continue REPL debugging. #### Chrome DevTool integration -With `rdbg --open=chrome` command will show the following message. +Using `rdbg --open=chrome` will show the following message: -``` +```console $ rdbg target.rb --open=chrome DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:43633) DEBUGGER: With Chrome browser, type the following URL in the address-bar: @@ -445,20 +455,25 @@ DEBUGGER: With Chrome browser, type the following URL in the address-bar: DEBUGGER: wait for debugger connection... ``` -Type `devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` in the address bar on Chrome browser, and you can continue the debugging with chrome browser. +Type the following in the address bar on Chrome browser, and you can continue the debugging with chrome browser: + +```txt +devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef` +``` -Also `open chrome` command works like `open vscode`. +Similar to VSCode, you can use `open chrome` to open the debugger in Chrome. -For more information about how to use Chrome debugging, you might want to read [here](https://developer.chrome.com/docs/devtools/). +For more information about how to use Chrome debugging, [see the devtools docs](https://developer.chrome.com/docs/devtools/). ## Configuration You can configure the debugger's behavior with debug commands and environment variables. -When the debug session is started, initial scripts are loaded so you can put your favorite configurations in the initial scripts. +When the debug session is started, some [initialization scripts](#initial-scripts) (e.g., `~/.rdbgrc`) are loaded, allowing you to configure the debugger's behavior to your needs and preferences. ### Configuration list -You can configure the debugger's behavior with environment variables and `config` command. Each configuration has an environment variable and a name which can be specified by `config` command. +You can configure the debugger's behavior with environment variables and `config` command. +Each configuration has an environment variable and a name which can be specified by `config` command. ``` # configuration example @@ -481,7 +496,7 @@ There are other environment variables: ### Initial scripts -If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains debug commands) when the debug session is started. +If there is a `~/.rdbgrc` file it is loaded as an initialization script (which contains debug commands) when the debug session is started. * `RUBY_DEBUG_INIT_SCRIPT` environment variable can specify the initial script file. * You can specify the initial script with `rdbg -x initial_script` (like gdb's `-x` option). @@ -489,7 +504,7 @@ If there is `~/.rdbgrc`, the file is loaded as an initial script (which contains Initial scripts are useful to write your favorite configurations. For example, you can set breakpoints with `break file:123` in `~/.rdbgrc`. -If there are `~/.rdbgrc.rb` is available, it is also loaded as a ruby script at same timing. +If there is a `~/.rdbgrc.rb` file it is also loaded as a Ruby script when the debug session is started. ## Debug command on the debug console @@ -498,16 +513,19 @@ On the debug console, you can use the following debug commands. There are additional features: * `` without debug command is almost the same as `pp `. - * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. So that the input `foo.bar` is the same as `pp foo.bar`. - * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. - * So the author (Koichi Sasada) recommends using `p`, `pp` or `eval` command to evaluate the Ruby expression every time. + * If the input line `` does *NOT* start with any debug command, the line `` will be evaluated as a Ruby expression, and the result will be printed with `pp` method. + So that the input `foo.bar` is the same as `pp foo.bar`. + * If `` is recognized as a debug command, of course, it is not evaluated as a Ruby expression but is executed as debug command. + For example, you can not evaluate such single-letter local variables `i`, `b`, `n`, `c` because they are single-letter debug commands. Use `p i` instead. + * For consistency, the author (Koichi Sasada) recommends using the `p`, `pp`, or `eval` command to evaluate the Ruby expression every time. * `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands. * `Ctrl-D` is equal to `quit` command. * [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing) -You can use the following debug commands. Each command should be written in 1 line. -The `[...]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. -The `<...>` notation means the argument. +You can use the following debug commands. +Each command should be written in 1 line. +The `[…]` notation means this part can be eliminated. For example, `s[tep]` means `s` or `step` is a valid command. `ste` is not valid. +The `<…>` notation means the argument. <%= DEBUGGER__.help %> @@ -524,7 +542,7 @@ To switch to the IRB console, simply use the `irb` command in the debug console. Once activated, you'll notice the prompt changes to: -```txt +```console irb:rdbg(main):001> ``` @@ -551,9 +569,12 @@ You can start debugging without `rdbg` command by requiring the following librar You need to require one of them at the very beginning of the application. Using `ruby -r` (for example `ruby -r debug/start target.rb`) is another way to invoke with debugger. -NOTE: Until Ruby 3.0, there is old `lib/debug.rb` standard library. So that if this gem is not installed, or if `Gemfile` missed to list this gem and `bundle exec` is used, you will see the following output: +NOTE: Until Ruby 3.0, there is old `lib/debug.rb` in the standard library. +`lib/debug.rb` was not maintained well in recent years, and the purpose of this library is to rewrite old `lib/debug.rb` with recent techniques. + +So, if this gem is not installed, or if the `Gemfile` doesn't include this gem and `bundle exec` is used, you will see the following output: -```shell +```console $ ruby -r debug -e0 .../2.7.3/lib/ruby/2.7.0/x86_64-linux/continuation.so: warning: callcc is obsolete; use Fiber instead Debug.rb @@ -563,16 +584,15 @@ Emacs support available. (rdb:1) ``` -`lib/debug.rb` was not maintained well in recent years, and the purpose of this library is to rewrite old `lib/debug.rb` with recent techniques. - #### Start by method -After loading `debug/session`, you can start a debug session with the following methods. They are convenient if you want to specify debug configurations in your program. +After loading `debug/session`, you can start a debug session with the following methods. +They are convenient if you want to specify debug configurations in your program. * `DEBUGGER__.start(**kw)`: start debug session with local console. -* `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket) -* `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket -* `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP +* `DEBUGGER__.open(**kw)`: open debug port with configuration (without configurations open with UNIX domain socket). +* `DEBUGGER__.open_unix(**kw)`: open debug port with UNIX domain socket. +* `DEBUGGER__.open_tcp(**kw)`: open debug port with TCP/IP. For example: @@ -586,24 +606,28 @@ DEBUGGER__.start(no_color: true, # disable colorize ### `binding.break` method -`binding.break` (or `binding.b`) set breakpoints at the written line. It also has several keywords. +`binding.break` (or `binding.b`) sets a breakpoint at that line. +It also has several keywords. If `do: 'command'` is specified, the debugger suspends the program, runs the `command` as a debug command, and continues the program. It is useful if you only want to call a debug command and don't want to stop there. +For example: -``` +```ruby def initialize @a = 1 binding.b do: 'info \n watch @a' end ``` -In this case, execute the `info` command then register a watch breakpoint for `@a` and continue to run. You can also use `;;` instead of `\n` to separate your commands. +In this case, execute the `info` command, then register a watch breakpoint for `@a` and continue to run. +You can also use `;;` instead of `\n` to separate your commands. If `pre: 'command'` is specified, the debugger suspends the program and runs the `command` as a debug command, and keeps suspended. It is useful if you have operations before suspend. +For example: -``` +```ruby def foo binding.b pre: 'p bar()' ... @@ -614,7 +638,7 @@ In this case, you can see the result of `bar()` every time you stop there. ## rdbg command help -``` +```console <%= `exe/rdbg --help` %> ``` @@ -625,7 +649,7 @@ In this case, you can see the result of `bar()` every time you stop there. # Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug. +Bug reports and pull requests are welcome on GitHub at [https://github.com/ruby/debug](). This debugger is not mature so your feedback will help us. Please also check the [contributing guideline](/CONTRIBUTING.md). From fb1cff5f7379a7b94c2669f0a3c632b64ae0213d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 4 Jun 2025 16:42:59 +0900 Subject: [PATCH 235/263] `no_repeat` option Entering an empty newline repeats the last command, such as `continue` or `list`. This configuration disable this feature. https://github.com/ruby/debug/issues/1098 --- lib/debug/config.rb | 1 + lib/debug/session.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/debug/config.rb b/lib/debug/config.rb index b083a5ca3..222e2a9d2 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -23,6 +23,7 @@ module DEBUGGER__ no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], + no_repeat: ['RUBY_DEBUG_NO_REPEAT', "UI: Do not repeat last line when empty line",:bool, "false"], irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 05dc7f508..c1558df68 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1144,7 +1144,7 @@ def register_default_command def process_command line if line.empty? - if @repl_prev_line + if @repl_prev_line && !CONFIG[:no_repeat] line = @repl_prev_line else return :retry From cf469f2b21710727abdd153b25a1e5123b002bb0 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 4 Jun 2025 16:52:50 +0900 Subject: [PATCH 236/263] The debug gem can abort when stepping into a rescue clause: ``` $ ruby -Ilib exe/rdbg rescue-test.rb [1, 7] in rescue-test.rb => 1| 1.times do 2| begin 3| raise 4| rescue 5| p 1 6| end 7| end =>#0
at rescue-test.rb:1 (rdbg) s # step command [1, 7] in rescue-test.rb 1| 1.times do 2| begin => 3| raise 4| rescue 5| p 1 6| end 7| end =>#0 block in
at rescue-test.rb:3 #1 Integer#times at :257 # and 1 frames (use `bt' command for all frames) (rdbg) s # step command /home/mame/work/debug/lib/debug/thread_client.rb:85:in 'DEBUGGER__::ThreadClient#default_frame_formatter': undefined method '+' for nil (NoMethodError) "#{colorize_blue("block")}#{args_str} in #{colorize_blue(block_loc + level)}" ^ from /home/mame/work/debug/lib/debug/thread_client.rb:755:in 'Method#call' from /home/mame/work/debug/lib/debug/thread_client.rb:755:in 'DEBUGGER__::ThreadClient#frame_str' from /home/mame/work/debug/lib/debug/thread_client.rb:742:in 'block in DEBUGGER__::ThreadClient#show_frames' from :257:in 'Integer#times' from /home/mame/work/debug/lib/debug/thread_client.rb:739:in 'DEBUGGER__::ThreadClient#show_frames' from /home/mame/work/debug/lib/debug/thread_client.rb:304:in 'DEBUGGER__::ThreadClient#suspend' from /home/mame/work/debug/lib/debug/thread_client.rb:358:in 'block in DEBUGGER__::ThreadClient#step_tp' from rescue-test.rb:5:in 'block in
' from :257:in 'Integer#times' from rescue-test.rb:1:in '
' rescue-test.rb:3:in 'block in
': unhandled exception from :257:in 'Integer#times' from rescue-test.rb:1:in '
' ``` This is because `rb_debug_inspector_backtrace_locations` returned a modified backtrace, which skips rescue/ensure frames, but `rb_debug_inspector_frame_XXX_get`'s index is considered for a raw backtrace, which includes rescue/ensure frames. The problem wil be fixed by https://github.com/ruby/ruby/pull/13510. However, now the backtrace includes rescue/ensure frames, so some tests in debug gem fails. This fixes the test failures. --- test/console/frame_block_identifier_test.rb | 4 +-- test/console/nested_break_test.rb | 2 +- test/console/rescue_test.rb | 28 +++++++++++++++++++++ test/console/trap_test.rb | 1 - 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 test/console/rescue_test.rb diff --git a/test/console/frame_block_identifier_test.rb b/test/console/frame_block_identifier_test.rb index a4349da19..dd483a583 100644 --- a/test/console/frame_block_identifier_test.rb +++ b/test/console/frame_block_identifier_test.rb @@ -46,8 +46,8 @@ def test_frame_block_identifier / 15\| end/, / 16\| end/, /=>\#0\tWhatever\#some_method at .*/, - / \#1\tblock in Kernel\#loop at :168/, - / \# and 2 frames \(use `bt' command for all frames\)/, + / \#1\t.*/, + / \# and (?:2|3) frames \(use `bt' command for all frames\)/, //, /Stop by \#0 BP \- Line .*/ ]) diff --git a/test/console/nested_break_test.rb b/test/console/nested_break_test.rb index d7e2437e5..c152b3f01 100644 --- a/test/console/nested_break_test.rb +++ b/test/console/nested_break_test.rb @@ -83,7 +83,7 @@ def test_multiple_nested_break assert_line_num 2 type 'p foo(142)' type 'bt' - assert_line_text(/\#7\s+
/) # TODO: can be changed + assert_line_text(/\#\d+\s+
/) type 'c' assert_line_text(/143/) diff --git a/test/console/rescue_test.rb b/test/console/rescue_test.rb new file mode 100644 index 000000000..f0225147b --- /dev/null +++ b/test/console/rescue_test.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative '../support/console_test_case' + +module DEBUGGER__ + class RescueTest < ConsoleTestCase + def program + <<~RUBY + 1| 1.times do + 2| begin + 3| raise + 4| rescue + 5| p :ok + 6| end + 7| end + RUBY + end + + def test_rescue + debug_code program, remote: false do + type 's' + type 's' + type 'c' + end + end + end if RUBY_VERSION.to_f >= 3.5 +end + diff --git a/test/console/trap_test.rb b/test/console/trap_test.rb index 17c4ccfa7..0f18e14ac 100644 --- a/test/console/trap_test.rb +++ b/test/console/trap_test.rb @@ -16,7 +16,6 @@ def test_sigint debug_code program, remote: false do type 'b 3' type 'c' - assert_line_num 2 assert_line_text(/is registered as SIGINT handler/) type 'sigint' assert_line_num 3 From dbcddaa626faf69607c92b80a1d4bf9934e03efd Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Thu, 5 Jun 2025 10:23:28 +0900 Subject: [PATCH 237/263] update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 412c6d652..6e737499e 100644 --- a/README.md +++ b/README.md @@ -495,6 +495,7 @@ config set no_color true * `RUBY_DEBUG_NO_RELINE` (`no_reline`): Do not use Reline library (default: false) * `RUBY_DEBUG_NO_HINT` (`no_hint`): Do not show the hint on the REPL (default: false) * `RUBY_DEBUG_NO_LINENO` (`no_lineno`): Do not show line numbers (default: false) + * `RUBY_DEBUG_NO_REPEAT` (`no_repeat`): Do not repeat last line when empty line (default: false) * `RUBY_DEBUG_IRB_CONSOLE` (`irb_console`): Use IRB as the console (default: false) * CONTROL From b0ca87e78b5e0985e7ff98148cc6a0ca6b6e78bc Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Wed, 4 Jun 2025 20:14:47 +0900 Subject: [PATCH 238/263] Explicitly skip TracePoint events in internal code In Ruby 3.5, `Kernel#caller_location` will not include `` frames. https://github.com/ruby/ruby/pull/13238 To skip the internal frames, explicitly check if `TracePoint#path` is a internal path or not. --- lib/debug/thread_client.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 259d69fcc..0e1fa42a1 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -350,6 +350,7 @@ def step_tp iter, events = [:line, :b_return, :return] next if tp.path.start_with?(__dir__) next if tp.path.start_with?('') next unless File.exist?(tp.path) if CONFIG[:skip_nosrc] + next if skip_internal_path?(tp.path) loc = caller_locations(1, 1).first next if skip_location?(loc) next if iter && (iter -= 1) > 0 @@ -369,6 +370,7 @@ def step_tp iter, events = [:line, :b_return, :return] next if tp.path.start_with?(__dir__) next if tp.path.start_with?('') next unless File.exist?(tp.path) if CONFIG[:skip_nosrc] + next if skip_internal_path?(tp.path) loc = caller_locations(1, 1).first next if skip_location?(loc) next if iter && (iter -= 1) > 0 From 32f55ff15bb7db620f1e2cd0e331b8b5605c1b03 Mon Sep 17 00:00:00 2001 From: Matthieu Prat Date: Fri, 10 Jan 2025 15:54:34 +0000 Subject: [PATCH 239/263] Fix help message of the `eval` command When running the `eval` command (or its alias, `call`) without an argument, you get the following error: ``` [REPL ERROR] #> debug-1.10.0/lib/debug/session.rb:934:in `block in register_default_command' debug-1.10.0/lib/debug/session.rb:1165:in `process_command' ... ``` ...instead of this hint: ``` To evaluate the variable `eval`, use `pp eval` instead. ``` I believe the regression was introduced in a402e73. To fix this issue, I was thinking of passing the command name alongside the argument in the `process_line` method but I wasn't sure this was worth it just for this hint. So I removed the hint altogether instead. --- lib/debug/session.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index c1558df68..5ab748c90 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -931,7 +931,6 @@ def register_default_command register_command 'eval', 'call' do |arg| if arg == nil || arg.empty? show_help 'eval' - @ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead." :retry else request_eval :call, arg From 29bb179f0cf8bfcb7da8a18212f00db605b127f0 Mon Sep 17 00:00:00 2001 From: jsxs Date: Thu, 5 Jun 2025 15:36:49 +0900 Subject: [PATCH 240/263] fix: handle UTF-8 history with empty LANG env --- lib/debug/console.rb | 46 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index b228086d9..dadc53363 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -167,7 +167,22 @@ def history_file def read_history_file if history && File.exist?(path = history_file) f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample - ["#{FH}#{f}".dup] + File.readlines(path) + begin + # Force UTF-8 encoding to handle history files with Unicode characters + lines = File.readlines(path, encoding: 'UTF-8') + ["#{FH}#{f}".dup] + lines + rescue ArgumentError, Encoding::UndefinedConversionError + # If UTF-8 reading fails, try with binary mode and force UTF-8 + begin + lines = File.readlines(path, mode: 'rb').map do |line| + line.force_encoding('UTF-8').scrub('?') + end + ["#{FH}#{f}".dup] + lines + rescue + # If all encoding attempts fail, return empty history to avoid crash + ["#{FH}#{f}".dup] + end + end else [] end @@ -191,10 +206,20 @@ def deactivate if !added_records.empty? && !path.empty? orig_records = read_history_file - open(history_file, 'w'){|f| + open(history_file, 'w', encoding: 'UTF-8'){|f| (orig_records + added_records).last(max).each{|line| - if !line.start_with?(FH) && !line.strip.empty? - f.puts line.strip + begin + # Ensure proper encoding before calling strip + if line.encoding != Encoding::UTF_8 + line = line.encode('UTF-8', invalid: :replace, undef: :replace) + end + stripped_line = line.strip + if !line.start_with?(FH) && !stripped_line.empty? + f.puts stripped_line + end + rescue Encoding::CompatibilityError, ArgumentError + # Skip lines that cannot be properly encoded to avoid crashes + next end } } @@ -204,8 +229,17 @@ def deactivate def load_history read_history_file.each{|line| - line.strip! - history << line unless line.empty? + begin + # Ensure proper encoding before calling strip! + if line.encoding != Encoding::UTF_8 + line = line.encode('UTF-8', invalid: :replace, undef: :replace) + end + line.strip! + history << line unless line.empty? + rescue Encoding::CompatibilityError, ArgumentError + # Skip lines that cannot be properly encoded to avoid crashes + next + end } if history.empty? history.count end From 64c0c723f3049743e2bf433f0e1082822693809c Mon Sep 17 00:00:00 2001 From: jsxs Date: Thu, 5 Jun 2025 15:53:26 +0900 Subject: [PATCH 241/263] fix: use String#scrub to handle encoding gracefully --- lib/debug/console.rb | 51 ++++++++++---------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index dadc53363..20eb7818e 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -167,22 +167,9 @@ def history_file def read_history_file if history && File.exist?(path = history_file) f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample - begin - # Force UTF-8 encoding to handle history files with Unicode characters - lines = File.readlines(path, encoding: 'UTF-8') - ["#{FH}#{f}".dup] + lines - rescue ArgumentError, Encoding::UndefinedConversionError - # If UTF-8 reading fails, try with binary mode and force UTF-8 - begin - lines = File.readlines(path, mode: 'rb').map do |line| - line.force_encoding('UTF-8').scrub('?') - end - ["#{FH}#{f}".dup] + lines - rescue - # If all encoding attempts fail, return empty history to avoid crash - ["#{FH}#{f}".dup] - end - end + # Read history file and scrub invalid characters to prevent encoding errors + lines = File.readlines(path).map(&:scrub) + ["#{FH}#{f}".dup] + lines else [] end @@ -206,20 +193,12 @@ def deactivate if !added_records.empty? && !path.empty? orig_records = read_history_file - open(history_file, 'w', encoding: 'UTF-8'){|f| + open(history_file, 'w'){|f| (orig_records + added_records).last(max).each{|line| - begin - # Ensure proper encoding before calling strip - if line.encoding != Encoding::UTF_8 - line = line.encode('UTF-8', invalid: :replace, undef: :replace) - end - stripped_line = line.strip - if !line.start_with?(FH) && !stripped_line.empty? - f.puts stripped_line - end - rescue Encoding::CompatibilityError, ArgumentError - # Skip lines that cannot be properly encoded to avoid crashes - next + # Use scrub to handle encoding issues gracefully + scrubbed_line = line.scrub.strip + if !line.start_with?(FH) && !scrubbed_line.empty? + f.puts scrubbed_line end } } @@ -229,17 +208,9 @@ def deactivate def load_history read_history_file.each{|line| - begin - # Ensure proper encoding before calling strip! - if line.encoding != Encoding::UTF_8 - line = line.encode('UTF-8', invalid: :replace, undef: :replace) - end - line.strip! - history << line unless line.empty? - rescue Encoding::CompatibilityError, ArgumentError - # Skip lines that cannot be properly encoded to avoid crashes - next - end + # Use scrub to handle encoding issues gracefully, then strip + line.scrub.strip! + history << line unless line.empty? } if history.empty? history.count end From bd9a813df844d81818d0af6fabfa650f8ce3ef86 Mon Sep 17 00:00:00 2001 From: jsxs Date: Thu, 5 Jun 2025 16:15:03 +0900 Subject: [PATCH 242/263] Fix load_history method --- lib/debug/console.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index 20eb7818e..c49324c13 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -209,7 +209,8 @@ def deactivate def load_history read_history_file.each{|line| # Use scrub to handle encoding issues gracefully, then strip - line.scrub.strip! + line.scrub! + line.strip! history << line unless line.empty? } if history.empty? history.count From 630dbfa08785b1cad6a72758247abaeb92e8ff4a Mon Sep 17 00:00:00 2001 From: Jason Garber Date: Sat, 30 Dec 2023 22:32:38 -0500 Subject: [PATCH 243/263] Add XDG support for history file (#1031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements XDG directory support for this gem's history file in accordance with the rules outlined in #1031: > For the history file: > > 1. prefer `~/.rdbg_history` if present, > 2. else, `$XDG_DATA_HOME/rdbg/history` if `$XDG_DATA_HOME` is set¹ > > ¹ There'd need to be a check for this file path. If it exists, great! > If not, create the path `$XDG_DATA_HOME/rdbg` and touch > `$XDG_DATA_HOME/rdbg/history`. See: https://github.com/ruby/debug/issues/1031#issuecomment-1855128422 --- lib/debug/console.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index c49324c13..2c89f035f 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -153,13 +153,20 @@ def history end def history_file - history_file = CONFIG[:history_file] + path = + if !CONFIG[:history_file].empty? && File.exist?(File.expand_path(CONFIG[:history_file])) + CONFIG[:history_file] + elsif (xdg_home = ENV['XDG_DATA_HOME']) + File.join(xdg_home, 'rdbg', 'history') + else + '~/.rdbg_history' + end - if !history_file.empty? - File.expand_path(history_file) - else - history_file - end + path = File.expand_path(path) + + FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(path) + + path end FH = "# Today's OMIKUJI: " From b63bd2ecae0751ddb7eb0b4f57375e5c236db767 Mon Sep 17 00:00:00 2001 From: Jason Garber Date: Sat, 30 Dec 2023 22:35:25 -0500 Subject: [PATCH 244/263] Add XDG support for rdbgrc file (#1031) This commit implements XDG directory support for this gem's `.rdbgrc` configuration file in accordance with the rules outlined in #1031: > 1. prefer `~/.rdbgrc` if present, > 2. else, `$XDG_CONFIG_HOME/rdbg/config` if `$XDG_CONFIG_HOME` is set > and `$XDG_CONFIG_HOME/rdbg/config` is present, > 3. else, no customized user configuration See: https://github.com/ruby/debug/issues/1031#issuecomment-1855128422 --- lib/debug/session.rb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 5ab748c90..d8ca80c4c 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2300,11 +2300,19 @@ def skip? end def self.load_rc - [[File.expand_path('~/.rdbgrc'), true], - [File.expand_path('~/.rdbgrc.rb'), true], - # ['./.rdbgrc', true], # disable because of security concern - [CONFIG[:init_script], false], - ].each{|(path, rc)| + rc_file_paths = [ + [File.expand_path('~/.rdbgrc'), true], + [File.expand_path('~/.rdbgrc.rb'), true], + # ['./.rdbgrc', true], # disable because of security concern + ] + + if (xdg_home = ENV["XDG_CONFIG_HOME"]) + rc_file_paths << [File.expand_path(File.join(xdg_home, "rdbg", "config")), true] + end + + rc_file_paths << [CONFIG[:init_script], false] + + rc_file_paths.each{|(path, rc)| next unless path next if rc && CONFIG[:no_rc] # ignore rc From f0579e4739eb5cd1e68ac15aeb3d519c0d9e6686 Mon Sep 17 00:00:00 2001 From: Jason Garber Date: Fri, 15 Mar 2024 16:20:20 -0400 Subject: [PATCH 245/263] Support config.rb in XDG config path (#1031) --- lib/debug/session.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index d8ca80c4c..3a101d6ee 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -2308,6 +2308,7 @@ def self.load_rc if (xdg_home = ENV["XDG_CONFIG_HOME"]) rc_file_paths << [File.expand_path(File.join(xdg_home, "rdbg", "config")), true] + rc_file_paths << [File.expand_path(File.join(xdg_home, "rdbg", "config.rb")), true] end rc_file_paths << [CONFIG[:init_script], false] From 43f80ff3a8eb71f9db725629bbcfbf700c92f69d Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 13 Jun 2025 16:15:49 +0900 Subject: [PATCH 246/263] fix hitory file path * Set `CONFIG[:history_file]` as nil, and ignore it if it is nil. * Respect `CONFIG[:history_file]` even if the path doesn't exists. * Respect `~/.rdbg_history` if exists for compatibility. * Use `XDG_STATE_HOME` if there is no configuration about history file. --- README.md | 2 +- lib/debug/config.rb | 2 +- lib/debug/console.rb | 26 ++++++++++++-------------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6e737499e..f429270b3 100644 --- a/README.md +++ b/README.md @@ -512,7 +512,7 @@ config set no_color true * `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop * `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. Commands should be separated by `;;` * `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb) (default: false) - * `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: ~/.rdbg_history) + * `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: $XDG_STATE_HOME/rdbg/history) * `RUBY_DEBUG_SAVE_HISTORY` (`save_history`): maximum save history lines (default: 10000) * REMOTE diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 222e2a9d2..906b41f00 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -40,7 +40,7 @@ module DEBUGGER__ init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], - history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"], + history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file (default: $XDG_STATE_HOME/rdbg/history)", :string, nil], save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], # remote setting diff --git a/lib/debug/console.rb b/lib/debug/console.rb index 2c89f035f..ec860b423 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -153,26 +153,24 @@ def history end def history_file - path = - if !CONFIG[:history_file].empty? && File.exist?(File.expand_path(CONFIG[:history_file])) - CONFIG[:history_file] - elsif (xdg_home = ENV['XDG_DATA_HOME']) - File.join(xdg_home, 'rdbg', 'history') - else - '~/.rdbg_history' - end - - path = File.expand_path(path) + case + when (path = CONFIG[:history_file]) && !path.empty? + path = File.expand_path(path) + when (path = File.expand_path("~/.rdbg_history")) && File.exist?(path) # for compatibility + # path + else + state_dir = ENV['XDG_STATE_HOME'] || File.join(Dir.home, '.local', 'state') + path = File.join(File.expand_path(state_dir), 'rdbg', 'history') + end FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(path) - path end FH = "# Today's OMIKUJI: " def read_history_file - if history && File.exist?(path = history_file) + if history && File.exist?(path = history_file()) f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample # Read history file and scrub invalid characters to prevent encoding errors lines = File.readlines(path).map(&:scrub) @@ -195,12 +193,12 @@ def load_history_if_not_loaded def deactivate if history && @init_history_lines added_records = history.to_a[@init_history_lines .. -1] - path = history_file + path = history_file() max = CONFIG[:save_history] if !added_records.empty? && !path.empty? orig_records = read_history_file - open(history_file, 'w'){|f| + open(history_file(), 'w'){|f| (orig_records + added_records).last(max).each{|line| # Use scrub to handle encoding issues gracefully scrubbed_line = line.scrub.strip From ec0a966101cfbff10c4bd787f58c1e060c331788 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Tue, 17 Jun 2025 11:28:31 -0400 Subject: [PATCH 247/263] Self-document the XDG_STATE_HOME fallback --- README.md | 2 +- lib/debug/config.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f429270b3..4d9dc631a 100644 --- a/README.md +++ b/README.md @@ -512,7 +512,7 @@ config set no_color true * `RUBY_DEBUG_INIT_SCRIPT` (`init_script`): debug command script path loaded at first stop * `RUBY_DEBUG_COMMANDS` (`commands`): debug commands invoked at first stop. Commands should be separated by `;;` * `RUBY_DEBUG_NO_RC` (`no_rc`): ignore loading ~/.rdbgrc(.rb) (default: false) - * `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: $XDG_STATE_HOME/rdbg/history) + * `RUBY_DEBUG_HISTORY_FILE` (`history_file`): history file (default: ${XDG_STATE_HOME-~/.local/state}/rdbg/history) * `RUBY_DEBUG_SAVE_HISTORY` (`save_history`): maximum save history lines (default: 10000) * REMOTE diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 906b41f00..5583671c4 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -40,7 +40,7 @@ module DEBUGGER__ init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], - history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file (default: $XDG_STATE_HOME/rdbg/history)", :string, nil], + history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file (default: ${XDG_STATE_HOME-~/.local/state}/rdbg/history)", :string, nil], save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], # remote setting From a86adbb7f7b4f5d88e15b7a0dce05a6cf568b8e1 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 18 Jun 2025 02:13:22 +0900 Subject: [PATCH 248/263] v1.11.0 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index f1d1e9467..0f05aed8e 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.10.0" + VERSION = "1.11.0" end From 14c8a546242a5e88ed8f47607629ffbef7d3315d Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 15 Jul 2025 11:00:04 +0200 Subject: [PATCH 249/263] Update imemo_mask to match ruby's The imemo mask has been `0xf` since Ruby 2.5 / ccfe37884ab566336380d0f21e15321d6382da8f This hasn't caused problems yet because the only possible conflict is `imemo_type = 15`, but it is not yet used. --- ext/debug/iseq_collector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/debug/iseq_collector.c b/ext/debug/iseq_collector.c index ae0beb487..6b8d355a9 100644 --- a/ext/debug/iseq_collector.c +++ b/ext/debug/iseq_collector.c @@ -10,7 +10,7 @@ size_t rb_obj_memsize_of(VALUE); // implementation specific. enum imemo_type { imemo_iseq = 7, - imemo_mask = 0x07 + imemo_mask = 0xf }; static inline enum imemo_type From 2791573fd24aef2091cbb30aa8750f3117781752 Mon Sep 17 00:00:00 2001 From: Dave Lamb Date: Sun, 30 Nov 2025 11:38:40 +0100 Subject: [PATCH 250/263] fix(DAP): Return unverified breakpoints instead of unsuccessful response --- lib/debug/server_dap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/server_dap.rb b/lib/debug/server_dap.rb index 7502182a4..907db2d1f 100644 --- a/lib/debug/server_dap.rb +++ b/lib/debug/server_dap.rb @@ -358,7 +358,7 @@ def process_request req } send_response req, breakpoints: (bps.map do |bp| {verified: true,} end) else - send_response req, success: false, message: "#{req_path} is not available" + send_response req, breakpoints: (args['breakpoints'].map do |bp| {verified: false, message: "#{req_path} could not be located; specify source location in launch.json with \"localfsMap\" or \"localfs\""} end) end when 'setFunctionBreakpoints' From 06342cd77a11af814c91726f7e5bc3f1974be9df Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 5 Dec 2025 17:18:23 +0900 Subject: [PATCH 251/263] catch any exception on `singletonclass` fix https://github.com/ruby/debug/issues/1162 --- lib/debug/frame_info.rb | 2 +- test/console/backtrace_test.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/debug/frame_info.rb b/lib/debug/frame_info.rb index 8fab332de..558f5466b 100644 --- a/lib/debug/frame_info.rb +++ b/lib/debug/frame_info.rb @@ -171,7 +171,7 @@ def parameters_info private def get_singleton_class obj obj.singleton_class # TODO: don't use it - rescue TypeError + rescue Exception nil end diff --git a/test/console/backtrace_test.rb b/test/console/backtrace_test.rb index 570d66c80..8c6056a6a 100644 --- a/test/console/backtrace_test.rb +++ b/test/console/backtrace_test.rb @@ -229,4 +229,31 @@ def test_backtrace_prints_without_hanging end end end + + class BrokenSingletonMethodBacktraceTest < ConsoleTestCase + def program + <<~RUBY + 1| class C + 2| def self.foo + 3| debugger + 4| end + 5| def singleton_class + 6| raise + 7| end + 8| def self.singleton_class + 9| eval(")") # SyntaxError + 10| end + 11| end + 12| C.foo + RUBY + end + + def test_raise_exception + debug_code program do + type 'c' + assert_line_text(/foo/) + type 'c' + end + end + end end From 1139d781ffde33a1ae6de04e718269cf8e4b0d09 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 03:26:13 +0900 Subject: [PATCH 252/263] support `b path: path_expr` break on each line on `path_expr`. --- lib/debug/breakpoint.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/debug/breakpoint.rb b/lib/debug/breakpoint.rb index 13e9c428b..78c4d2174 100644 --- a/lib/debug/breakpoint.rb +++ b/lib/debug/breakpoint.rb @@ -23,7 +23,7 @@ def safe_eval b, expr b.eval(expr) rescue Exception => e puts "[EVAL ERROR]" - puts " expr: #{expr}" + puts " expr: #{expr.inspect}" puts " err: #{e} (#{e.class})" puts "Error caused by #{self}." nil @@ -352,7 +352,7 @@ def setup next if ThreadClient.current.management? next if skip_path?(tp.path) - if need_suspend? safe_eval(tp.binding, @cond) + if @cond.nil? || need_suspend?(safe_eval(tp.binding, @cond)) suspend end } From bc97d3387deb4357419e9ebc6c40f809d1858527 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 03:33:06 +0900 Subject: [PATCH 253/263] add a test for `b path: ...` --- test/console/break_test.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/console/break_test.rb b/test/console/break_test.rb index 2b8f989ce..4733360ff 100644 --- a/test/console/break_test.rb +++ b/test/console/break_test.rb @@ -255,6 +255,17 @@ def test_break_only_stops_when_path_matches end end + def test_break_only_path + with_extra_tempfile "foohtml" do |extra_file| + debug_code(program(extra_file.path)) do + type "break path: #{extra_file.path}" + type 'c' + assert_line_text(/#{extra_file.path}/) + type 'c' + end + end + end + def test_the_path_option_supersede_skip_path_config # skips the extra_file's breakpoint with_extra_tempfile do |extra_file| From 24f95d637d96d92eb249e1ca45f3550832b5307f Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 03:52:38 +0900 Subject: [PATCH 254/263] catch up 4.0.0 backtrace change --- test/protocol/catch_raw_dap_test.rb | 58 ++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/test/protocol/catch_raw_dap_test.rb b/test/protocol/catch_raw_dap_test.rb index 273c3dd10..3e6a3c437 100644 --- a/test/protocol/catch_raw_dap_test.rb +++ b/test/protocol/catch_raw_dap_test.rb @@ -646,7 +646,9 @@ def test_catching_any_exception_works_correctly success: true, message: "Success", body: { - stackFrames: [ + stackFrames: + RUBY_VERSION < "4.0.0" ? [ + ## { name: "[C] Integer#/", line: 4, @@ -690,6 +692,40 @@ def test_catching_any_exception_works_correctly sourceReference: 0 }, id: 5 + }] : [ + ## RUBY_VERSION >= '4.0.0' + { + name: "Foo::Bar.a", + line: 4, + column: 1, + source: { + name: /#{File.basename temp_file_path}/, + path: /#{temp_file_path}/, + sourceReference: 0 + }, + id: 2 + }, + { + name: "", + line: 7, + column: 1, + source: { + name: /#{File.basename temp_file_path}/, + path: /#{temp_file_path}/, + sourceReference: 0 + }, + id: 3 + }, + { + name: "
", + line: 1, + column: 1, + source: { + name: /#{File.basename temp_file_path}/, + path: /#{temp_file_path}/, + sourceReference: 0 + }, + id: 4 } ] } @@ -738,7 +774,7 @@ def test_catching_any_exception_works_correctly }, type: "request" }, - { + RUBY_VERSION < "4.0.0" ? { seq: 19, type: "response", command: "variables", @@ -765,6 +801,24 @@ def test_catching_any_exception_works_correctly } ] } + } : # RUBY_VERSION >= "4.0.0" + { + "type": "response", + "command": "variables", + "request_seq": 16, + "success": true, + "message": "Success", + "body": { + "variables": [ + { + "name": "%self", + "value": "Foo::Bar", + "type": "Class", + "variablesReference": 5, + "indexedVariables": 0, + "namedVariables": 1 + }] + } }, { seq: 17, From c1c1c8e2533096e82d2888170f18d7cc990407fd Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 5 Dec 2025 18:38:11 +0900 Subject: [PATCH 255/263] use `Kernel.__callee__` for BasicObject fix https://github.com/ruby/debug/issues/1152 --- lib/debug/thread_client.rb | 2 +- test/console/record_test.rb | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/debug/thread_client.rb b/lib/debug/thread_client.rb index 0e1fa42a1..0a92fe356 100644 --- a/lib/debug/thread_client.rb +++ b/lib/debug/thread_client.rb @@ -1310,7 +1310,7 @@ def initialize frame._local_variables = b.local_variables.map{|name| [name, b.local_variable_get(name)] }.to_h - frame._callee = b.eval('__callee__') + frame._callee = b.eval('::Kernel.__callee__') end } append(frames) diff --git a/test/console/record_test.rb b/test/console/record_test.rb index 6b6f99798..9cf32756e 100644 --- a/test/console/record_test.rb +++ b/test/console/record_test.rb @@ -315,4 +315,24 @@ def test_1663647719 end end end + + class RecordOnBasicClassTest < ConsoleTestCase + def program + <<~RUBY + 1| class Test < BasicObject + 2| def test + 3| 42 + 4| end + 5| end + 6| Test.new.test + RUBY + end + + def test_issue1152 + debug_code program do + type 'record on' + type 'c' + end + end + end end From 553373a59f655177dabb2cef952ad1fae1d55fa4 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 05:00:57 +0900 Subject: [PATCH 256/263] omit on older version because it is fragile. --- test/protocol/eval_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/protocol/eval_test.rb b/test/protocol/eval_test.rb index 5f32358f2..8f78128f7 100644 --- a/test/protocol/eval_test.rb +++ b/test/protocol/eval_test.rb @@ -49,6 +49,7 @@ class EvaluateOnSomeFramesTest < ProtocolTestCase RUBY def test_eval_evaluates_arithmetic_expressions + omit 'this test is fragile on older versions' if RUBY_VERSION < '3.4.0' run_protocol_scenario PROGRAM do req_add_breakpoint 4 req_continue From 88d762c8c9b157e3a2627ac3de0df1d5cb8dace5 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 05:11:08 +0900 Subject: [PATCH 257/263] FileUtils is needed --- lib/debug/console.rb | 1 + lib/debug/server.rb | 1 + test/support/test_case.rb | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/debug/console.rb b/lib/debug/console.rb index ec860b423..211af9e49 100644 --- a/lib/debug/console.rb +++ b/lib/debug/console.rb @@ -163,6 +163,7 @@ def history_file path = File.join(File.expand_path(state_dir), 'rdbg', 'history') end + require 'fileutils' FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(path) path end diff --git a/lib/debug/server.rb b/lib/debug/server.rb index 41f3bca13..0a3c7d266 100644 --- a/lib/debug/server.rb +++ b/lib/debug/server.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'socket' +require 'fileutils' require_relative 'config' require_relative 'version' diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 2d1d26f96..8ae965372 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -7,6 +7,7 @@ require 'timeout' require 'json' require 'rbconfig' +require 'fileutils' require_relative '../../lib/debug/client' require_relative 'assertions' From bad4d38f8330219b62f2b253d59146f5a71fd39a Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Fri, 19 Dec 2025 10:54:49 +0900 Subject: [PATCH 258/263] v1.11.1 --- lib/debug/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debug/version.rb b/lib/debug/version.rb index 0f05aed8e..d5b3811a8 100644 --- a/lib/debug/version.rb +++ b/lib/debug/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module DEBUGGER__ - VERSION = "1.11.0" + VERSION = "1.11.1" end From 2897edad6d2c2eeb49ffe915192c54572dbe6c82 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Mon, 30 Mar 2026 09:44:38 -0700 Subject: [PATCH 259/263] Scrub invalid UTF-8 bytes from debuggee output in tests setup_remote_debuggee reads lines from PTY and matches them against regexps, but Regexp#=== raises ArgumentError when the line contains invalid UTF-8 byte sequences. This has been causing random CI failures: https://github.com/ruby/ruby/actions/runs/23754369209/job/69204936437 Use String#scrub to replace invalid bytes before matching. --- test/support/test_case.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/support/test_case.rb b/test/support/test_case.rb index 8ae965372..9797975f2 100644 --- a/test/support/test_case.rb +++ b/test/support/test_case.rb @@ -173,6 +173,7 @@ def setup_remote_debuggee(cmd) Timeout.timeout(TIMEOUT_SEC) do line = remote_info.r.gets + line = line.scrub if line remote_info.debuggee_backlog << line # wait for two lines (order is unstable) From 1de33e7405bf479b8fc394b90cb92122c6ffe4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lara?= Date: Sat, 4 Apr 2026 21:30:20 -0300 Subject: [PATCH 260/263] fix: deadlock using IRB integration on Rails applications When using `debugger` in a rails console using IRB integration, the second `continue` causes a fatal deadlock: "No live threads left. Deadlock?" The root cause is that `leave_subsession` pops `@subsession_stack` and sets `@tc = nil` before `thread_stopper.disable` takes full effect. In that window, the thread_stopper TracePoint fires on the main thread (back in IRB's eval loop), and since `@tc` is nil, the guard `tc == @tc` no longer protects it. The main thread is paused via `on_pause`, but the session server is already blocked on `@q_evt.pop` -- neither can wake the other. The fix for this is addiing `next unless in_subsession?` as the first guard in thread_stopper. Once `leave_subsession` has popped the stack, in_subsession? returns false and the TracePoint becomes a no-op even if it hasn't been disabled yet. --- lib/debug/session.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/debug/session.rb b/lib/debug/session.rb index 3a101d6ee..99c78af1d 100644 --- a/lib/debug/session.rb +++ b/lib/debug/session.rb @@ -1678,6 +1678,14 @@ def get_thread_client th = Thread.current private def thread_stopper TracePoint.new(:line) do + # When leave_subsession pops the subsession stack and sets @tc = nil, + # there is a window before the TracePoint is disabled where this block + # can still fire on other threads. Without this guard, the main thread + # (back in IRB's eval loop) would be paused by on_pause, but the + # session server is already waiting on @q_evt.pop -- causing a mutual + # deadlock ("No live threads left. Deadlock?"). + next unless in_subsession? + # run on each thread tc = ThreadClient.current next if tc.management? From 95997c297acd7adc20be81b52d2d1405805671d2 Mon Sep 17 00:00:00 2001 From: Marin Rukavina Date: Tue, 27 Jan 2026 18:07:56 +0100 Subject: [PATCH 261/263] Fix showing help message on wrong options --- exe/rdbg | 2 +- lib/debug/config.rb | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/exe/rdbg b/exe/rdbg index 52b93d8ce..14b5e978c 100755 --- a/exe/rdbg +++ b/exe/rdbg @@ -1,7 +1,7 @@ #!/usr/bin/env ruby require_relative '../lib/debug/config' -config = DEBUGGER__::Config::parse_argv(ARGV) +config, opt = *DEBUGGER__::Config::parse_argv(ARGV) # mode is not an actual configuration option # it's only used to carry the result of parse_argv here diff --git a/lib/debug/config.rb b/lib/debug/config.rb index 5583671c4..a5af775af 100644 --- a/lib/debug/config.rb +++ b/lib/debug/config.rb @@ -74,7 +74,7 @@ def initialize argv raise 'Can not make multiple configurations in one process' end - config = self.class.parse_argv(argv) + config, _ = *self.class.parse_argv(argv) # apply defaults CONFIG_SET.each do |k, config_detail| @@ -277,12 +277,6 @@ def self.parse_argv argv config[key] = parse_config_value(key, val) end } - return config if !argv || argv.empty? - - if argv.kind_of? String - require 'shellwords' - argv = Shellwords.split(argv) - end require 'optparse' require_relative 'version' @@ -433,6 +427,13 @@ def self.parse_argv argv o.separator ' Please use the remote debugging feature carefully.' end + return [config, opt] if !argv || argv.empty? + + if argv.kind_of? String + require 'shellwords' + argv = Shellwords.split(argv) + end + opt.parse!(argv) if argv.empty? @@ -442,7 +443,7 @@ def self.parse_argv argv end end - config + [config, opt] end def self.config_to_env_hash config From 9dc2024a5a05116b3d38afbc5579d9503d8913f3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Apr 2026 12:35:05 +0000 Subject: [PATCH 262/263] Update color test for IRB struct member name coloring The latest IRB version wraps struct member names in CYAN, so the expected output in test_colored_inspect_color_objects_if_use_colorize needs to wrap `foo` with CYAN/CLEAR escape sequences. --- test/console/color_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/console/color_test.rb b/test/console/color_test.rb index 8f62dce45..cb3fef1cb 100644 --- a/test/console/color_test.rb +++ b/test/console/color_test.rb @@ -33,7 +33,7 @@ def bar end end - { "#{GREEN}##{CLEAR}\n": dummy_class.new('b'), + { "#{GREEN}##{CLEAR}\n": dummy_class.new('b'), "#{RED}#{BOLD}\"#{CLEAR}#{RED}hoge#{CLEAR}#{RED}#{BOLD}\"#{CLEAR}\n": 'hoge'}.each do |k, v| expected = k.to_s obj = v From ce67347fd16bda4873731cdc8f68a99822981091 Mon Sep 17 00:00:00 2001 From: Arpit Jain Date: Fri, 15 May 2026 14:51:22 +0900 Subject: [PATCH 263/263] ci: declare workflow-level contents: read on 5 workflows Pins the default GITHUB_TOKEN to contents: read on the workflows in .github/workflows/ that don't call a GitHub API beyond the initial checkout. The other workflows in this directory are left implicit because they need write scopes that a maintainer is better placed to declare. Motivation: CVE-2025-30066 (March 2025 tj-actions/changed-files compromise) exfiltrated GITHUB_TOKEN from workflow logs. Per-workflow caps bound runtime authority irrespective of repo or org default, give drift protection if the default ever widens, and are credited per-file by the OpenSSF Scorecard Token-Permissions check. YAML validated locally with yaml.safe_load. Signed-off-by: Arpit Jain --- .github/workflows/protocol.yml | 3 +++ .github/workflows/ruby-macos.yaml | 3 +++ .github/workflows/ruby.yml | 3 +++ .github/workflows/test_test.yml | 3 +++ .github/workflows/truffleruby.yml | 3 +++ 5 files changed, 15 insertions(+) diff --git a/.github/workflows/protocol.yml b/.github/workflows/protocol.yml index fb9c3b204..666ab4375 100644 --- a/.github/workflows/protocol.yml +++ b/.github/workflows/protocol.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: ruby-versions: uses: ruby/actions/.github/workflows/ruby_versions.yml@master diff --git a/.github/workflows/ruby-macos.yaml b/.github/workflows/ruby-macos.yaml index 6e4d6bc06..e48eeb2cf 100644 --- a/.github/workflows/ruby-macos.yaml +++ b/.github/workflows/ruby-macos.yaml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: ruby-versions: uses: ruby/actions/.github/workflows/ruby_versions.yml@master diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 2666dc282..f53c61da7 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: ruby-versions: uses: ruby/actions/.github/workflows/ruby_versions.yml@master diff --git a/.github/workflows/test_test.yml b/.github/workflows/test_test.yml index f4339bf35..72e31affb 100644 --- a/.github/workflows/test_test.yml +++ b/.github/workflows/test_test.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: ruby-versions: uses: ruby/actions/.github/workflows/ruby_versions.yml@master diff --git a/.github/workflows/truffleruby.yml b/.github/workflows/truffleruby.yml index 2d05d2ce7..a3ec885bd 100644 --- a/.github/workflows/truffleruby.yml +++ b/.github/workflows/truffleruby.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ master ] +permissions: + contents: read + jobs: truffleruby: runs-on: ubuntu-latest