debug 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14d08935b209386adbc7a1172ae0d43feb7bf31c9483aa177946fa0669db69e8
4
- data.tar.gz: '01917758f048b2927a6e42b8965985477fed13011b3cd7626220ea8d1aad42fd'
3
+ metadata.gz: 1bac91980fb350e0e37a0639612064bba25a8e441661a6d797e0d9f996ce0205
4
+ data.tar.gz: 3294757150ec0731ccadd0c26a57c8e920c0479e4a967b4900e999dae4afcf9c
5
5
  SHA512:
6
- metadata.gz: 6381058fe16c43d79afdc04db1dcfcff6bd3c65216ce9bc9a03b02c26dbe098011879128c2e4f3ed31b1f7cf279b590fd641b4030f6cb6308434d65d17e51110
7
- data.tar.gz: c2896cca900dea7f5f4456b30f8dc4ecbed6886da74c46033e82bcda37da561759f2bd3b9a702eef7603785c17989f437b4f186817ad458edd16371c7b879688
6
+ metadata.gz: 7a0259c1f8fa904d9a425be5035e2642de89e69cd81cc61bd81bae2e9e7b17dbd18a78addce9e5ed8e3c7723417c0de1113a26922131760e490e77e91bb8493d
7
+ data.tar.gz: fd55333ccf690b4338729a2b84d55a21464ba2de71bdf5edcb0b82f309594477333224eb3be0a89c6b7c477042c4f904f8b743f74bba3931f6db4de7a9ff7dd9
data/CONTRIBUTING.md CHANGED
@@ -149,10 +149,10 @@ If the file already exists, **only method** will be added to it.
149
149
  ```ruby
150
150
  # frozen_string_literal: true
151
151
 
152
- require_relative '../support/test_case'
152
+ require_relative '../support/console_test_case'
153
153
 
154
154
  module DEBUGGER__
155
- class FooTest < TestCase
155
+ class FooTest < ConsoleTestCase
156
156
  def program
157
157
  <<~RUBY
158
158
  1| module Foo
data/README.md CHANGED
@@ -26,7 +26,7 @@ New debug.rb has several advantages:
26
26
  * Support threads (almost done) and ractors (TODO).
27
27
  * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
28
28
  * Show parameters on backtrace command.
29
- * Support recording & reply debugging.
29
+ * Support recording & replay debugging.
30
30
 
31
31
  # Installation
32
32
 
@@ -563,9 +563,9 @@ The `<...>` notation means the argument.
563
563
  * `u[ntil]`
564
564
  * Similar to `next` command, but only stop later lines or the end of the current frame.
565
565
  * Similar to gdb's `advance` command.
566
- * `u[ntil] <[file:]line>
566
+ * `u[ntil] <[file:]line>`
567
567
  * Run til the program reaches given location or the end of the current frame.
568
- * `u[ntil] <name>
568
+ * `u[ntil] <name>`
569
569
  * Run til the program invokes a method `<name>`. `<name>` can be a regexp with `/name/`.
570
570
  * `c` or `cont` or `continue`
571
571
  * Resume the program.
data/Rakefile CHANGED
@@ -35,9 +35,14 @@ task :check_readme do
35
35
  end
36
36
  end
37
37
 
38
+ desc "Run debug.gem test-framework tests"
39
+ Rake::TestTask.new(:test_test) do |t|
40
+ t.test_files = FileList["test/support/*_test.rb"]
41
+ end
42
+
38
43
  desc "Run all debugger console related tests"
39
44
  Rake::TestTask.new(:test_console) do |t|
40
- t.test_files = FileList["test/console/*_test.rb", "test/support/*_test.rb"]
45
+ t.test_files = FileList["test/console/*_test.rb"]
41
46
  end
42
47
 
43
48
  desc "Run all debugger protocols (CAP & DAP) related tests"
@@ -46,7 +51,7 @@ Rake::TestTask.new(:test_protocol) do |t|
46
51
  end
47
52
 
48
53
  task test: 'test_console' do
49
- warn '`rake test` doesn\'t run protocol tests. Use `rake test-all` to test all.'
54
+ warn '`rake test` doesn\'t run protocol tests. Use `rake test_all` to test all.'
50
55
  end
51
56
 
52
- task test_all: [:test_console, :test_protocol]
57
+ task test_all: [:test_test, :test_console, :test_protocol]
data/TODO.md CHANGED
@@ -2,22 +2,22 @@
2
2
 
3
3
  ## Basic functionality
4
4
 
5
- * Support Ractors
6
- * Signal (SIGINT) trap handling
5
+ * Support Fibers and Ractors
7
6
 
8
7
  ## UI
9
8
 
9
+ * Multi-line support
10
10
  * Completion for Ruby's code
11
11
  * Interactive breakpoint setting
12
12
  * Interactive record & play debugging
13
13
  * irb integration
14
- * Web browser integrated UI
15
- * History file
16
14
 
17
15
  ## Debug command
18
16
 
19
- * Breakpoints
20
- * Lightweight pending method break points with Ruby 3.1 feature (TP:method_added)
21
17
  * Watch points
22
- * Lightweight watchpoints for instance variables with Ruby 3.1 features (TP:ivar_set)
23
- * Faster `next`/`finish` command by specifying target code.
18
+ * Lightweight watchpoints for instance variables with Ruby 3.3 features (TP:ivar_set)
19
+ * Alias
20
+
21
+ ## Debug port
22
+
23
+ * Debug port for monitoring
@@ -101,10 +101,6 @@ module DEBUGGER__
101
101
  def generate_label(name)
102
102
  colorize(" BP - #{name} ", [:YELLOW, :BOLD, :REVERSE])
103
103
  end
104
-
105
- def pending_until_load?
106
- false
107
- end
108
104
  end
109
105
 
110
106
  if RUBY_VERSION.to_f <= 2.7
@@ -163,10 +159,6 @@ module DEBUGGER__
163
159
  @pending = !@iseq
164
160
  end
165
161
 
166
- def pending_until_load?
167
- @pending
168
- end
169
-
170
162
  def setup
171
163
  return unless @type
172
164
 
@@ -207,6 +199,8 @@ module DEBUGGER__
207
199
  if @pending && !@oneshot
208
200
  DEBUGGER__.info "#{self} is activated."
209
201
  end
202
+
203
+ @pending = false
210
204
  end
211
205
 
212
206
  def activate_exact iseq, events, line
@@ -299,6 +293,10 @@ module DEBUGGER__
299
293
  def inspect
300
294
  "<#{self.class.name} #{self.to_s}>"
301
295
  end
296
+
297
+ def path_is? path
298
+ DEBUGGER__.compare_path(@path, path)
299
+ end
302
300
  end
303
301
 
304
302
  class CatchBreakpoint < Breakpoint
data/lib/debug/config.rb CHANGED
@@ -265,6 +265,8 @@ module DEBUGGER__
265
265
  require 'optparse'
266
266
  require_relative 'version'
267
267
 
268
+ have_shown_version = false
269
+
268
270
  opt = OptionParser.new do |o|
269
271
  o.banner = "#{$0} [options] -- [debuggee options]"
270
272
  o.separator ''
@@ -372,6 +374,16 @@ module DEBUGGER__
372
374
  o.separator ''
373
375
  o.separator 'Other options:'
374
376
 
377
+ o.on('-v', 'Show version number') do
378
+ puts o.ver
379
+ have_shown_version = true
380
+ end
381
+
382
+ o.on('--version', 'Show version number and exit') do
383
+ puts o.ver
384
+ exit
385
+ end
386
+
375
387
  o.on("-h", "--help", "Print help") do
376
388
  puts o
377
389
  exit
@@ -395,6 +407,14 @@ module DEBUGGER__
395
407
 
396
408
  opt.parse!(argv)
397
409
 
410
+ if argv.empty?
411
+ case
412
+ when have_shown_version && config[:mode] == :start
413
+ pp config
414
+ exit
415
+ end
416
+ end
417
+
398
418
  config
399
419
  end
400
420
 
@@ -425,8 +445,9 @@ module DEBUGGER__
425
445
  unless (dir_uid = fs.uid) == (uid = Process.uid)
426
446
  raise "#{path} uid is #{dir_uid}, but Process.uid is #{uid}"
427
447
  end
428
- unless (dir_mode = fs.mode) == 040700 # 4: dir, 7:rwx
429
- raise "#{path}'s mode is #{dir_mode.to_s(8)} (should be 040700)"
448
+
449
+ if fs.world_writable? && !fs.sticky?
450
+ raise "#{path} is world writable but not sticky"
430
451
  end
431
452
 
432
453
  path
data/lib/debug/prelude.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  return if ENV['RUBY_DEBUG_ENABLE'] == '0'
4
- return if defined?(::DEBUGGER__)
4
+ return if defined?(::DEBUGGER__::Session)
5
5
 
6
6
  # Put the following line in your login script (e.g. ~/.bash_profile) with modified path:
7
7
  #
data/lib/debug/server.rb CHANGED
@@ -406,14 +406,13 @@ module DEBUGGER__
406
406
  require_relative 'server_cdp'
407
407
 
408
408
  @uuid = SecureRandom.uuid
409
- unless @chrome_pid = UI_CDP.setup_chrome(@local_addr.inspect_sockaddr, @uuid)
410
- DEBUGGER__.warn <<~EOS
411
- With Chrome browser, type the following URL in the address-bar:
409
+ @chrome_pid = UI_CDP.setup_chrome(@local_addr.inspect_sockaddr, @uuid)
410
+ DEBUGGER__.warn <<~EOS
411
+ With Chrome browser, type the following URL in the address-bar:
412
412
 
413
- devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid}
413
+ devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid}
414
414
 
415
- EOS
416
- end
415
+ EOS
417
416
  end
418
417
 
419
418
  def accept
@@ -34,25 +34,26 @@ module DEBUGGER__
34
34
 
35
35
  loop do
36
36
  res = ws_client.extract_data
37
- case
38
- when res['id'] == 1 && target_info = res.dig('result', 'targetInfos')
37
+ case res['id']
38
+ when 1
39
+ target_info = res.dig('result', 'targetInfos')
39
40
  page = target_info.find{|t| t['type'] == 'page'}
40
41
  ws_client.send id: 2, method: 'Target.attachToTarget',
41
42
  params: {
42
43
  targetId: page['targetId'],
43
44
  flatten: true
44
45
  }
45
- when res['id'] == 2
46
+ when 2
46
47
  s_id = res.dig('result', 'sessionId')
47
48
  # TODO: change id
48
49
  ws_client.send sessionId: s_id, id: 100, method: 'Network.enable'
49
50
  ws_client.send sessionId: s_id, id: 3,
50
51
  method: 'Page.enable'
51
- when res['id'] == 3
52
+ when 3
52
53
  s_id = res['sessionId']
53
54
  ws_client.send sessionId: s_id, id: 4,
54
55
  method: 'Page.getFrameTree'
55
- when res['id'] == 4
56
+ when 4
56
57
  s_id = res['sessionId']
57
58
  f_id = res.dig('result', 'frameTree', 'frame', 'id')
58
59
  ws_client.send sessionId: s_id, id: 5,
@@ -61,17 +62,19 @@ module DEBUGGER__
61
62
  url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}",
62
63
  frameId: f_id
63
64
  }
64
- when res['method'] == 'Network.webSocketWillSendHandshakeRequest'
65
- s_id = res['sessionId']
66
- # Display the console by entering ESC key
67
- ws_client.send sessionId: s_id, id: 101, # TODO: change id
68
- method:"Input.dispatchKeyEvent",
69
- params: {
70
- type:"keyDown",
71
- windowsVirtualKeyCode:27 # ESC key
72
- }
73
- when res['id'] == 101
65
+ when 101
74
66
  break
67
+ else
68
+ if res['method'] == 'Network.webSocketWillSendHandshakeRequest'
69
+ s_id = res['sessionId']
70
+ # Display the console by entering ESC key
71
+ ws_client.send sessionId: s_id, id: 101, # TODO: change id
72
+ method:"Input.dispatchKeyEvent",
73
+ params: {
74
+ type:"keyDown",
75
+ windowsVirtualKeyCode:27 # ESC key
76
+ }
77
+ end
75
78
  end
76
79
  end
77
80
  pid
@@ -95,7 +98,6 @@ module DEBUGGER__
95
98
  candidates = ['C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
96
99
  path = get_chrome_path candidates
97
100
  end
98
- uuid = SecureRandom.uuid
99
101
  # The path is based on https://github.com/sindresorhus/open/blob/v8.4.0/index.js#L128.
100
102
  stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell")
101
103
  tf = Tempfile.create(['debug-', '.txt'])
@@ -447,11 +449,7 @@ module DEBUGGER__
447
449
  end
448
450
 
449
451
  def send_response req, **res
450
- if res.empty?
451
- @ws_server.send id: req['id'], result: {}
452
- else
453
- @ws_server.send id: req['id'], result: res
454
- end
452
+ @ws_server.send id: req['id'], result: res
455
453
  end
456
454
 
457
455
  def send_fail_response req, **res
@@ -459,11 +457,7 @@ module DEBUGGER__
459
457
  end
460
458
 
461
459
  def send_event method, **params
462
- if params.empty?
463
- @ws_server.send method: method, params: {}
464
- else
465
- @ws_server.send method: method, params: params
466
- end
460
+ @ws_server.send method: method, params: params
467
461
  end
468
462
 
469
463
  INVALID_REQUEST = -32600
@@ -554,6 +548,9 @@ module DEBUGGER__
554
548
  activate_bp bps
555
549
  end
556
550
  send_response req
551
+ when 'Debugger.pause'
552
+ send_response req
553
+ Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
557
554
 
558
555
  # breakpoint
559
556
  when 'Debugger.getPossibleBreakpoints'
@@ -561,35 +558,31 @@ module DEBUGGER__
561
558
  when 'Debugger.setBreakpointByUrl'
562
559
  line = req.dig('params', 'lineNumber')
563
560
  if regexp = req.dig('params', 'urlRegex')
564
- path = regexp.match(/(.*)\|/)[1].gsub("\\", "")
565
- cond = req.dig('params', 'condition')
566
- src = get_source_code path
567
- end_line = src.lines.count
568
- line = end_line if line > end_line
569
561
  b_id = "1:#{line}:#{regexp}"
570
- if cond != ''
571
- SESSION.add_line_breakpoint(path, line + 1, cond: cond)
572
- else
573
- SESSION.add_line_breakpoint(path, line + 1)
574
- end
575
562
  bps[b_id] = bps.size
576
- # Because we need to return scriptId, responses are returned in SESSION thread.
577
- req['params']['scriptId'] = path
578
- req['params']['lineNumber'] = line
579
- req['params']['breakpointId'] = b_id
580
- @q_msg << req
563
+ path = regexp.match(/(.*)\|/)[1].gsub("\\", "")
564
+ add_line_breakpoint(req, b_id, path)
581
565
  elsif url = req.dig('params', 'url')
582
566
  b_id = "#{line}:#{url}"
583
- send_response req,
584
- breakpointId: b_id,
585
- locations: []
586
- elsif hash = req.dig('params', 'scriptHash')
587
- b_id = "#{line}:#{hash}"
588
- send_response req,
589
- breakpointId: b_id,
590
- locations: []
567
+ # When breakpoints are set in Script snippet, non-existent path such as "snippet:///Script%20snippet%20%231" sent.
568
+ # That's why we need to check it here.
569
+ if File.exist? url
570
+ bps[b_id] = bps.size
571
+ add_line_breakpoint(req, b_id, url)
572
+ else
573
+ send_response req,
574
+ breakpointId: b_id,
575
+ locations: []
576
+ end
591
577
  else
592
- raise 'Unsupported'
578
+ if hash = req.dig('params', 'scriptHash')
579
+ b_id = "#{line}:#{hash}"
580
+ send_response req,
581
+ breakpointId: b_id,
582
+ locations: []
583
+ else
584
+ raise 'Unsupported'
585
+ end
593
586
  end
594
587
  when 'Debugger.removeBreakpoint'
595
588
  b_id = req.dig('params', 'breakpointId')
@@ -628,6 +621,24 @@ module DEBUGGER__
628
621
  @q_msg << 'continue'
629
622
  end
630
623
 
624
+ def add_line_breakpoint req, b_id, path
625
+ cond = req.dig('params', 'condition')
626
+ line = req.dig('params', 'lineNumber')
627
+ src = get_source_code path
628
+ end_line = src.lines.count
629
+ line = end_line if line > end_line
630
+ if cond != ''
631
+ SESSION.add_line_breakpoint(path, line + 1, cond: cond)
632
+ else
633
+ SESSION.add_line_breakpoint(path, line + 1)
634
+ end
635
+ # Because we need to return scriptId, responses are returned in SESSION thread.
636
+ req['params']['scriptId'] = path
637
+ req['params']['lineNumber'] = line
638
+ req['params']['breakpointId'] = b_id
639
+ @q_msg << req
640
+ end
641
+
631
642
  def del_bp bps, k
632
643
  return bps unless idx = bps[k]
633
644
 
@@ -665,37 +676,28 @@ module DEBUGGER__
665
676
  def cleanup_reader
666
677
  super
667
678
  Process.kill :KILL, @chrome_pid if @chrome_pid
679
+ rescue Errno::ESRCH # continue if @chrome_pid process is not found
668
680
  end
669
681
 
670
682
  ## Called by the SESSION thread
671
683
 
672
- def respond req, **result
673
- send_response req, **result
674
- end
675
-
676
- def respond_fail req, **result
677
- send_fail_response req, **result
678
- end
679
-
680
- def fire_event event, **result
681
- if result.empty?
682
- send_event event
683
- else
684
- send_event event, **result
685
- end
686
- end
684
+ alias respond send_response
685
+ alias respond_fail send_fail_response
686
+ alias fire_event send_event
687
687
 
688
688
  def sock skip: false
689
689
  yield $stderr
690
690
  end
691
691
 
692
- def puts result
692
+ def puts result=''
693
693
  # STDERR.puts "puts: #{result}"
694
694
  # send_event 'output', category: 'stderr', output: "PUTS!!: " + result.to_s
695
695
  end
696
696
  end
697
697
 
698
698
  class Session
699
+ include GlobalVariablesHelper
700
+
699
701
  # FIXME: unify this method with ThreadClient#propertyDescriptor.
700
702
  def get_type obj
701
703
  case obj
@@ -750,8 +752,12 @@ module DEBUGGER__
750
752
  fid = @frame_map[frame_id]
751
753
  request_tc [:cdp, :scope, req, fid]
752
754
  when 'global'
753
- vars = global_variables.sort.map do |name|
754
- gv = eval(name.to_s)
755
+ vars = safe_global_variables.sort.map do |name|
756
+ begin
757
+ gv = eval(name.to_s)
758
+ rescue Errno::ENOENT
759
+ gv = nil
760
+ end
755
761
  prop = {
756
762
  name: name,
757
763
  value: {
@@ -831,7 +837,7 @@ module DEBUGGER__
831
837
  end
832
838
  end
833
839
 
834
- def cdp_event args
840
+ def process_protocol_result args
835
841
  type, req, result = args
836
842
 
837
843
  case type
@@ -1021,7 +1027,7 @@ module DEBUGGER__
1021
1027
  result[:data] = evaluate_result exception
1022
1028
  result[:reason] = 'exception'
1023
1029
  end
1024
- event! :cdp_result, :backtrace, req, result
1030
+ event! :protocol_result, :backtrace, req, result
1025
1031
  when :evaluate
1026
1032
  res = {}
1027
1033
  fid, expr, group = args
@@ -1040,7 +1046,7 @@ module DEBUGGER__
1040
1046
  case expr
1041
1047
  # Chrome doesn't read instance variables
1042
1048
  when /\A\$\S/
1043
- global_variables.each{|gvar|
1049
+ safe_global_variables.each{|gvar|
1044
1050
  if gvar.to_s == expr
1045
1051
  result = eval(gvar.to_s)
1046
1052
  break false
@@ -1066,7 +1072,7 @@ module DEBUGGER__
1066
1072
  begin
1067
1073
  orig_stdout = $stdout
1068
1074
  $stdout = StringIO.new
1069
- result = current_frame.binding.eval(expr.to_s, '(DEBUG CONSOLE)')
1075
+ result = b.eval(expr.to_s, '(DEBUG CONSOLE)')
1070
1076
  rescue Exception => e
1071
1077
  result = e
1072
1078
  res[:exceptionDetails] = exceptionDetails(e, 'Uncaught')
@@ -1082,7 +1088,7 @@ module DEBUGGER__
1082
1088
  end
1083
1089
 
1084
1090
  res[:result] = evaluate_result(result)
1085
- event! :cdp_result, :evaluate, req, message: message, response: res, output: output
1091
+ event! :protocol_result, :evaluate, req, message: message, response: res, output: output
1086
1092
  when :scope
1087
1093
  fid = args.shift
1088
1094
  frame = @target_frames[fid]
@@ -1105,7 +1111,7 @@ module DEBUGGER__
1105
1111
  vars.unshift variable(name, val)
1106
1112
  end
1107
1113
  end
1108
- event! :cdp_result, :scope, req, vars
1114
+ event! :protocol_result, :scope, req, vars
1109
1115
  when :properties
1110
1116
  oid = args.shift
1111
1117
  result = []
@@ -1147,14 +1153,14 @@ module DEBUGGER__
1147
1153
  }
1148
1154
  prop += [internalProperty('#class', M_CLASS.bind_call(obj))]
1149
1155
  end
1150
- event! :cdp_result, :properties, req, result: result, internalProperties: prop
1156
+ event! :protocol_result, :properties, req, result: result, internalProperties: prop
1151
1157
  when :exception
1152
1158
  oid = args.shift
1153
1159
  exc = nil
1154
1160
  if obj = @obj_map[oid]
1155
1161
  exc = exceptionDetails obj, obj.to_s
1156
1162
  end
1157
- event! :cdp_result, :exception, req, exceptionDetails: exc
1163
+ event! :protocol_result, :exception, req, exceptionDetails: exc
1158
1164
  end
1159
1165
  end
1160
1166
 
@@ -125,6 +125,7 @@ module DEBUGGER__
125
125
  def dap_setup bytes
126
126
  CONFIG.set_config no_color: true
127
127
  @seq = 0
128
+ @send_lock = Mutex.new
128
129
 
129
130
  case self
130
131
  when UI_UnixDomainServer
@@ -212,9 +213,13 @@ module DEBUGGER__
212
213
  if sock = @sock
213
214
  kw[:seq] = @seq += 1
214
215
  str = JSON.dump(kw)
215
- sock.write "Content-Length: #{str.bytesize}\r\n\r\n#{str}"
216
+ @send_lock.synchronize do
217
+ sock.write "Content-Length: #{str.bytesize}\r\n\r\n#{str}"
218
+ end
216
219
  show_protocol '<', str
217
220
  end
221
+ rescue Errno::EPIPE => e
222
+ $stderr.puts "#{e.inspect} rescued during sending message"
218
223
  end
219
224
 
220
225
  def send_response req, success: true, message: nil, **kw
@@ -246,17 +251,17 @@ module DEBUGGER__
246
251
  end
247
252
 
248
253
  def recv_request
249
- r = IO.select([@sock])
254
+ IO.select([@sock])
250
255
 
251
256
  @session.process_group.sync do
252
257
  raise RetryBecauseCantRead unless IO.select([@sock], nil, nil, 0)
253
258
 
254
- case header = @sock.gets
259
+ case @sock.gets
255
260
  when /Content-Length: (\d+)/
256
261
  b = @sock.read(2)
257
262
  raise b.inspect unless b == "\r\n"
258
263
 
259
- l = @sock.read(s = $1.to_i)
264
+ l = @sock.read($1.to_i)
260
265
  show_protocol :>, l
261
266
  JSON.load(l)
262
267
  when nil
@@ -309,7 +314,6 @@ module DEBUGGER__
309
314
  when 'setBreakpoints'
310
315
  req_path = args.dig('source', 'path')
311
316
  path = UI_DAP.local_to_remote_path(req_path)
312
-
313
317
  if path
314
318
  SESSION.clear_line_breakpoints path
315
319
 
@@ -436,11 +440,12 @@ module DEBUGGER__
436
440
  when 'evaluate'
437
441
  expr = req.dig('arguments', 'expression')
438
442
  if /\A\s*,(.+)\z/ =~ expr
439
- dbg_expr = $1
443
+ dbg_expr = $1.strip
444
+ dbg_expr.split(';;') { |cmd| @q_msg << cmd }
445
+
440
446
  send_response req,
441
- result: "",
447
+ result: "(rdbg:command) #{dbg_expr}",
442
448
  variablesReference: 0
443
- debugger do: dbg_expr
444
449
  else
445
450
  @q_msg << req
446
451
  end
@@ -452,7 +457,11 @@ module DEBUGGER__
452
457
  @q_msg << req
453
458
 
454
459
  else
455
- raise "Unknown request: #{req.inspect}"
460
+ if respond_to? mid = "custom_dap_request_#{req['command']}"
461
+ __send__ mid, req
462
+ else
463
+ raise "Unknown request: #{req.inspect}"
464
+ end
456
465
  end
457
466
  end
458
467
  ensure
@@ -516,6 +525,8 @@ module DEBUGGER__
516
525
  end
517
526
 
518
527
  class Session
528
+ include GlobalVariablesHelper
529
+
519
530
  def find_waiting_tc id
520
531
  @th_clients.each{|th, tc|
521
532
  return tc if tc.id == id && tc.waiting?
@@ -540,7 +551,7 @@ module DEBUGGER__
540
551
  when 'stackTrace'
541
552
  tid = req.dig('arguments', 'threadId')
542
553
 
543
- if tc = find_waiting_tc(tid)
554
+ if find_waiting_tc(tid)
544
555
  request_tc [:dap, :backtrace, req]
545
556
  else
546
557
  fail_response req
@@ -549,7 +560,7 @@ module DEBUGGER__
549
560
  frame_id = req.dig('arguments', 'frameId')
550
561
  if @frame_map[frame_id]
551
562
  tid, fid = @frame_map[frame_id]
552
- if tc = find_waiting_tc(tid)
563
+ if find_waiting_tc(tid)
553
564
  request_tc [:dap, :scopes, req, fid]
554
565
  else
555
566
  fail_response req
@@ -562,8 +573,12 @@ module DEBUGGER__
562
573
  if ref = @var_map[varid]
563
574
  case ref[0]
564
575
  when :globals
565
- vars = global_variables.sort.map do |name|
566
- gv = eval(name.to_s)
576
+ vars = safe_global_variables.sort.map do |name|
577
+ begin
578
+ gv = eval(name.to_s)
579
+ rescue Exception => e
580
+ gv = e.inspect
581
+ end
567
582
  {
568
583
  name: name,
569
584
  value: gv.inspect,
@@ -581,7 +596,7 @@ module DEBUGGER__
581
596
  frame_id = ref[1]
582
597
  tid, fid = @frame_map[frame_id]
583
598
 
584
- if tc = find_waiting_tc(tid)
599
+ if find_waiting_tc(tid)
585
600
  request_tc [:dap, :scope, req, fid]
586
601
  else
587
602
  fail_response req
@@ -590,7 +605,7 @@ module DEBUGGER__
590
605
  when :variable
591
606
  tid, vid = ref[1], ref[2]
592
607
 
593
- if tc = find_waiting_tc(tid)
608
+ if find_waiting_tc(tid)
594
609
  request_tc [:dap, :variable, req, vid]
595
610
  else
596
611
  fail_response req
@@ -609,7 +624,7 @@ module DEBUGGER__
609
624
  tid, fid = @frame_map[frame_id]
610
625
  expr = req.dig('arguments', 'expression')
611
626
 
612
- if tc = find_waiting_tc(tid)
627
+ if find_waiting_tc(tid)
613
628
  request_tc [:dap, :evaluate, req, fid, expr, context]
614
629
  else
615
630
  fail_response req
@@ -630,7 +645,7 @@ module DEBUGGER__
630
645
  frame_id = req.dig('arguments', 'frameId')
631
646
  tid, fid = @frame_map[frame_id]
632
647
 
633
- if tc = find_waiting_tc(tid)
648
+ if find_waiting_tc(tid)
634
649
  text = req.dig('arguments', 'text')
635
650
  line = req.dig('arguments', 'line')
636
651
  if col = req.dig('arguments', 'column')
@@ -641,11 +656,15 @@ module DEBUGGER__
641
656
  fail_response req
642
657
  end
643
658
  else
644
- raise "Unknown DAP request: #{req.inspect}"
659
+ if respond_to? mid = "custom_dap_request_#{req['command']}"
660
+ __send__ mid, req
661
+ else
662
+ raise "Unknown request: #{req.inspect}"
663
+ end
645
664
  end
646
665
  end
647
666
 
648
- def dap_event args
667
+ def process_protocol_result args
649
668
  # puts({dap_event: args}.inspect)
650
669
  type, req, result = args
651
670
 
@@ -693,7 +712,11 @@ module DEBUGGER__
693
712
  when :completions
694
713
  @ui.respond req, result
695
714
  else
696
- raise "unsupported: #{args.inspect}"
715
+ if respond_to? mid = "custom_dap_request_event_#{type}"
716
+ __send__ mid, req, result
717
+ else
718
+ raise "unsupported: #{args.inspect}"
719
+ end
697
720
  end
698
721
  end
699
722
 
@@ -721,9 +744,8 @@ module DEBUGGER__
721
744
  end
722
745
 
723
746
  class ThreadClient
724
-
725
747
  MAX_LENGTH = 180
726
-
748
+
727
749
  def value_inspect obj, short: true
728
750
  # TODO: max length should be configuarable?
729
751
  str = DEBUGGER__.safe_inspect obj, short: short, max_length: MAX_LENGTH
@@ -735,6 +757,14 @@ module DEBUGGER__
735
757
  end
736
758
  end
737
759
 
760
+ def dap_eval b, expr, _context, prompt: '(repl_eval)'
761
+ begin
762
+ b.eval(expr.to_s, prompt)
763
+ rescue Exception => e
764
+ e
765
+ end
766
+ end
767
+
738
768
  def process_dap args
739
769
  # pp tc: self, args: args
740
770
  type = args.shift
@@ -772,7 +802,7 @@ module DEBUGGER__
772
802
  }
773
803
  end
774
804
 
775
- event! :dap_result, :backtrace, req, {
805
+ event! :protocol_result, :backtrace, req, {
776
806
  stackFrames: frames,
777
807
  totalFrames: @target_frames.size,
778
808
  }
@@ -789,7 +819,7 @@ module DEBUGGER__
789
819
  0
790
820
  end
791
821
 
792
- event! :dap_result, :scopes, req, scopes: [{
822
+ event! :protocol_result, :scopes, req, scopes: [{
793
823
  name: 'Local variables',
794
824
  presentationHint: 'locals',
795
825
  # variablesReference: N, # filled by SESSION
@@ -800,7 +830,7 @@ module DEBUGGER__
800
830
  name: 'Global variables',
801
831
  presentationHint: 'globals',
802
832
  variablesReference: 1, # GLOBAL
803
- namedVariables: global_variables.size,
833
+ namedVariables: safe_global_variables.size,
804
834
  indexedVariables: 0,
805
835
  expensive: false,
806
836
  }]
@@ -811,7 +841,7 @@ module DEBUGGER__
811
841
  variable(var, val)
812
842
  end
813
843
 
814
- event! :dap_result, :scope, req, variables: vars, tid: self.id
844
+ event! :protocol_result, :scope, req, variables: vars, tid: self.id
815
845
  when :variable
816
846
  vid = args.shift
817
847
  obj = @var_map[vid]
@@ -837,10 +867,11 @@ module DEBUGGER__
837
867
  }
838
868
  when String
839
869
  vars = [
840
- variable('#length', obj.length),
870
+ variable('#lengthddsfsd', obj.length),
841
871
  variable('#encoding', obj.encoding),
842
872
  ]
843
- vars << variable('#dump', NaiveString.new(obj)) if obj.length > MAX_LENGTH
873
+ printed_str = value_inspect(obj)
874
+ vars << variable('#dump', NaiveString.new(obj)) if printed_str.end_with?('...')
844
875
  when Class, Module
845
876
  vars << variable('%ancestors', obj.ancestors[1..])
846
877
  when Range
@@ -858,7 +889,7 @@ module DEBUGGER__
858
889
  end
859
890
  end
860
891
  end
861
- event! :dap_result, :variable, req, variables: (vars || []), tid: self.id
892
+ event! :protocol_result, :variable, req, variables: (vars || []), tid: self.id
862
893
 
863
894
  when :evaluate
864
895
  fid, expr, context = args
@@ -872,12 +903,7 @@ module DEBUGGER__
872
903
 
873
904
  case context
874
905
  when 'repl', 'watch'
875
- begin
876
- result = b.eval(expr.to_s, '(DEBUG CONSOLE)')
877
- rescue Exception => e
878
- result = e
879
- end
880
-
906
+ result = dap_eval b, expr, context, prompt: '(DEBUG CONSOLE)'
881
907
  when 'hover'
882
908
  case expr
883
909
  when /\A\@\S/
@@ -887,7 +913,7 @@ module DEBUGGER__
887
913
  message = "Error: Not defined instance variable: #{expr.inspect}"
888
914
  end
889
915
  when /\A\$\S/
890
- global_variables.each{|gvar|
916
+ safe_global_variables.each{|gvar|
891
917
  if gvar.to_s == expr
892
918
  result = eval(gvar.to_s)
893
919
  break false
@@ -918,7 +944,7 @@ module DEBUGGER__
918
944
  result = 'Error: Can not evaluate on this frame'
919
945
  end
920
946
 
921
- event! :dap_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result)
947
+ event! :protocol_result, :evaluate, req, message: message, tid: self.id, **evaluate_result(result)
922
948
 
923
949
  when :completions
924
950
  fid, text = args
@@ -928,7 +954,7 @@ module DEBUGGER__
928
954
  words = IRB::InputCompletor::retrieve_completion_data(word, bind: b).compact
929
955
  end
930
956
 
931
- event! :dap_result, :completions, req, targets: (words || []).map{|phrase|
957
+ event! :protocol_result, :completions, req, targets: (words || []).map{|phrase|
932
958
  detail = nil
933
959
 
934
960
  if /\b([_a-zA-Z]\w*[!\?]?)\z/ =~ phrase
@@ -951,7 +977,11 @@ module DEBUGGER__
951
977
  }
952
978
 
953
979
  else
954
- raise "Unknown req: #{args.inspect}"
980
+ if respond_to? mid = "custom_dap_request_#{type}"
981
+ __send__ mid, req
982
+ else
983
+ raise "Unknown request: #{args.inspect}"
984
+ end
955
985
  end
956
986
  end
957
987
 
data/lib/debug/session.rb CHANGED
@@ -128,16 +128,16 @@ module DEBUGGER__
128
128
  @obj_map = {} # { object_id => ... } for CDP
129
129
 
130
130
  @tp_thread_begin = nil
131
+ @tp_thread_end = nil
132
+
131
133
  @commands = {}
132
134
  @unsafe_context = false
133
135
 
134
- has_keep_script_lines = RubyVM.respond_to? :keep_script_lines
136
+ @has_keep_script_lines = RubyVM.respond_to? :keep_script_lines
135
137
 
136
138
  @tp_load_script = TracePoint.new(:script_compiled){|tp|
137
- if !has_keep_script_lines || bps_pending_until_load?
138
- eval_script = tp.eval_script unless has_keep_script_lines
139
- ThreadClient.current.on_load tp.instruction_sequence, eval_script
140
- end
139
+ eval_script = tp.eval_script unless @has_keep_script_lines
140
+ ThreadClient.current.on_load tp.instruction_sequence, eval_script
141
141
  }
142
142
  @tp_load_script.enable
143
143
 
@@ -169,12 +169,17 @@ module DEBUGGER__
169
169
  @ui = ui if ui
170
170
 
171
171
  @tp_thread_begin&.disable
172
+ @tp_thread_end&.disable
172
173
  @tp_thread_begin = nil
173
-
174
+ @tp_thread_end = nil
174
175
  @ui.activate self, on_fork: on_fork
175
176
 
176
177
  q = Queue.new
178
+ first_q = Queue.new
177
179
  @session_server = Thread.new do
180
+ # make sure `@session_server` is assigned
181
+ first_q.pop; first_q = nil
182
+
178
183
  Thread.current.name = 'DEBUGGER__::SESSION@server'
179
184
  Thread.current.abort_on_exception = true
180
185
 
@@ -192,10 +197,16 @@ module DEBUGGER__
192
197
  end
193
198
  @tp_thread_begin.enable
194
199
 
200
+ @tp_thread_end = TracePoint.new(:thread_end) do |tp|
201
+ @th_clients.delete(Thread.current)
202
+ end
203
+ @tp_thread_end.enable
204
+
195
205
  # session start
196
206
  q << true
197
207
  session_server_main
198
208
  end
209
+ first_q << :ok
199
210
 
200
211
  q.pop
201
212
  end
@@ -205,6 +216,7 @@ module DEBUGGER__
205
216
  @thread_stopper.disable
206
217
  @tp_load_script.disable
207
218
  @tp_thread_begin.disable
219
+ @tp_thread_end.disable
208
220
  @bps.each_value{|bp| bp.disable}
209
221
  @th_clients.each_value{|thc| thc.close}
210
222
  @tracers.values.each{|t| t.disable}
@@ -219,11 +231,13 @@ module DEBUGGER__
219
231
 
220
232
  # activate new ui
221
233
  @tp_thread_begin.disable
234
+ @tp_thread_end.disable
222
235
  @ui.activate self
223
236
  if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread)
224
237
  thc.mark_as_management
225
238
  end
226
239
  @tp_thread_begin.enable
240
+ @tp_thread_end.enable
227
241
  end
228
242
 
229
243
  def pop_event
@@ -329,16 +343,13 @@ module DEBUGGER__
329
343
  opt = ev_args[3]
330
344
  add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt)
331
345
  else
332
- # ignore
346
+ stop_all_threads
333
347
  end
334
348
 
335
349
  wait_command_loop
336
350
 
337
- when :dap_result
338
- dap_event ev_args # server.rb
339
- wait_command_loop
340
- when :cdp_result
341
- cdp_event ev_args
351
+ when :protocol_result
352
+ process_protocol_result ev_args
342
353
  wait_command_loop
343
354
  end
344
355
  end
@@ -480,9 +491,9 @@ module DEBUGGER__
480
491
  # * `u[ntil]`
481
492
  # * Similar to `next` command, but only stop later lines or the end of the current frame.
482
493
  # * Similar to gdb's `advance` command.
483
- # * `u[ntil] <[file:]line>
494
+ # * `u[ntil] <[file:]line>`
484
495
  # * Run til the program reaches given location or the end of the current frame.
485
- # * `u[ntil] <name>
496
+ # * `u[ntil] <name>`
486
497
  # * Run til the program invokes a method `<name>`. `<name>` can be a regexp with `/name/`.
487
498
  register_command 'u', 'until',
488
499
  repeat: true,
@@ -889,13 +900,13 @@ module DEBUGGER__
889
900
  # * `p <expr>`
890
901
  # * Evaluate like `p <expr>` on the current frame.
891
902
  register_command 'p' do |arg|
892
- request_tc [:eval, :p, arg.to_s]
903
+ request_eval :p, arg.to_s
893
904
  end
894
905
 
895
906
  # * `pp <expr>`
896
907
  # * Evaluate like `pp <expr>` on the current frame.
897
908
  register_command 'pp' do |arg|
898
- request_tc [:eval, :pp, arg.to_s]
909
+ request_eval :pp, arg.to_s
899
910
  end
900
911
 
901
912
  # * `eval <expr>`
@@ -906,7 +917,7 @@ module DEBUGGER__
906
917
  @ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
907
918
  :retry
908
919
  else
909
- request_tc [:eval, :call, arg]
920
+ request_eval :call, arg
910
921
  end
911
922
  end
912
923
 
@@ -917,7 +928,7 @@ module DEBUGGER__
917
928
  @ui.puts "not supported on the remote console."
918
929
  :retry
919
930
  end
920
- request_tc [:eval, :irb]
931
+ request_eval :irb, nil
921
932
  end
922
933
 
923
934
  ### Trace
@@ -1137,7 +1148,7 @@ module DEBUGGER__
1137
1148
  @repl_prev_line = nil
1138
1149
  check_unsafe
1139
1150
 
1140
- request_tc [:eval, :pp, line]
1151
+ request_eval :pp, line
1141
1152
  end
1142
1153
 
1143
1154
  rescue Interrupt
@@ -1153,6 +1164,11 @@ module DEBUGGER__
1153
1164
  return :retry
1154
1165
  end
1155
1166
 
1167
+ def request_eval type, src
1168
+ restart_all_threads
1169
+ request_tc [:eval, type, src]
1170
+ end
1171
+
1156
1172
  def step_command type, arg
1157
1173
  if type == :until
1158
1174
  leave_subsession [:step, type, arg]
@@ -1321,10 +1337,6 @@ module DEBUGGER__
1321
1337
 
1322
1338
  # breakpoint management
1323
1339
 
1324
- def bps_pending_until_load?
1325
- @bps.any?{|key, bp| bp.pending_until_load?}
1326
- end
1327
-
1328
1340
  def iterate_bps
1329
1341
  deleted_bps = []
1330
1342
  i = 0
@@ -1500,7 +1512,7 @@ module DEBUGGER__
1500
1512
  def clear_line_breakpoints path
1501
1513
  path = resolve_path(path)
1502
1514
  clear_breakpoints do |k, bp|
1503
- bp.is_a?(LineBreakpoint) && DEBUGGER__.compare_path(k.first, path)
1515
+ bp.is_a?(LineBreakpoint) && bp.path_is?(path)
1504
1516
  end
1505
1517
  rescue Errno::ENOENT
1506
1518
  # just ignore
@@ -1524,7 +1536,7 @@ module DEBUGGER__
1524
1536
  # tracers
1525
1537
 
1526
1538
  def add_tracer tracer
1527
- if @tracers.has_key? tracer.key
1539
+ if @tracers[tracer.key]&.enabled?
1528
1540
  tracer.disable
1529
1541
  @ui.puts "Duplicated tracer: #{tracer}"
1530
1542
  else
@@ -1724,25 +1736,26 @@ module DEBUGGER__
1724
1736
  file_path, reloaded = @sr.add(iseq, src)
1725
1737
  @ui.event :load, file_path, reloaded
1726
1738
 
1727
- pending_line_breakpoints = @bps.find_all do |key, bp|
1728
- LineBreakpoint === bp && !bp.iseq
1729
- end
1730
-
1731
- pending_line_breakpoints.each do |_key, bp|
1732
- if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
1733
- bp.try_activate iseq
1734
- end
1735
- end
1736
-
1737
- if reloaded
1738
- @bps.find_all do |key, bp|
1739
- LineBreakpoint === bp && DEBUGGER__.compare_path(bp.path, file_path)
1739
+ # check breakpoints
1740
+ if file_path
1741
+ @bps.find_all do |_key, bp|
1742
+ LineBreakpoint === bp && bp.path_is?(file_path)
1740
1743
  end.each do |_key, bp|
1741
- @bps.delete bp.key # to allow duplicate
1742
- if nbp = LineBreakpoint.copy(bp, iseq)
1743
- add_bp nbp
1744
+ if !bp.iseq
1745
+ bp.try_activate iseq
1746
+ elsif reloaded
1747
+ @bps.delete bp.key # to allow duplicate
1748
+ if nbp = LineBreakpoint.copy(bp, iseq)
1749
+ add_bp nbp
1750
+ end
1744
1751
  end
1745
1752
  end
1753
+ else # !file_path => file_path is not existing
1754
+ @bps.find_all do |_key, bp|
1755
+ LineBreakpoint === bp && !bp.iseq && DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
1756
+ end.each do |_key, bp|
1757
+ bp.try_activate iseq
1758
+ end
1746
1759
  end
1747
1760
  end
1748
1761
 
@@ -2438,7 +2451,7 @@ module DEBUGGER__
2438
2451
  end
2439
2452
 
2440
2453
  module DaemonInterceptor
2441
- def daemon
2454
+ def daemon(*args)
2442
2455
  return super unless defined?(SESSION) && SESSION.active?
2443
2456
 
2444
2457
  _, child_hook = __fork_setup_for_debugger(:child)
@@ -34,7 +34,7 @@ module DEBUGGER__
34
34
  end
35
35
 
36
36
  def add iseq, src
37
- # do nothing
37
+ # only manage loaded file names
38
38
  if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path)
39
39
  if @loaded_file_map.has_key? path
40
40
  return path, true # reloaded
@@ -49,7 +49,7 @@ module DEBUGGER__
49
49
  lines = iseq.script_lines&.map(&:chomp)
50
50
  line = iseq.first_line
51
51
  if line > 1
52
- lines = [*([''] * (line - 1)), *lines]
52
+ [*([''] * (line - 1)), *lines]
53
53
  else
54
54
  lines
55
55
  end
@@ -29,7 +29,7 @@ module DEBUGGER__
29
29
  end
30
30
 
31
31
  def skip_internal_path?(path)
32
- path.start_with?(__dir__) || path.start_with?('<internal:')
32
+ path.start_with?(__dir__) || path.delete_prefix('!eval:').start_with?('<internal:')
33
33
  end
34
34
 
35
35
  def skip_location?(loc)
@@ -38,6 +38,13 @@ module DEBUGGER__
38
38
  end
39
39
  end
40
40
 
41
+ module GlobalVariablesHelper
42
+ SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze
43
+ def safe_global_variables
44
+ global_variables.reject{|name| SKIP_GLOBAL_LIST.include? name }
45
+ end
46
+ end
47
+
41
48
  class ThreadClient
42
49
  def self.current
43
50
  if thc = Thread.current[:DEBUGGER__ThreadClient]
@@ -50,6 +57,7 @@ module DEBUGGER__
50
57
 
51
58
  include Color
52
59
  include SkipPathHelper
60
+ include GlobalVariablesHelper
53
61
 
54
62
  attr_reader :thread, :id, :recorder, :check_bp_fulfillment_map
55
63
 
@@ -636,9 +644,8 @@ module DEBUGGER__
636
644
  end
637
645
  end
638
646
 
639
- SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze
640
647
  def show_globals pat
641
- global_variables.sort.each{|name|
648
+ safe_global_variables.sort.each{|name|
642
649
  next if SKIP_GLOBAL_LIST.include? name
643
650
 
644
651
  value = eval(name.to_s)
@@ -1223,7 +1230,15 @@ module DEBUGGER__
1223
1230
  rescue SuspendReplay, SystemExit, Interrupt
1224
1231
  raise
1225
1232
  rescue Exception => e
1226
- pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
1233
+ STDERR.puts e.cause.inspect
1234
+ STDERR.puts e.inspect
1235
+ Thread.list.each{|th|
1236
+ STDERR.puts "@@@ #{th}"
1237
+ th.backtrace.each{|b|
1238
+ STDERR.puts " > #{b}"
1239
+ }
1240
+ }
1241
+ p ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
1227
1242
  raise
1228
1243
  ensure
1229
1244
  @returning = false
data/lib/debug/tracer.rb CHANGED
@@ -54,6 +54,10 @@ module DEBUGGER__
54
54
  @tracer.disable
55
55
  end
56
56
 
57
+ def enabled?
58
+ @tracer.enabled?
59
+ end
60
+
57
61
  def description
58
62
  nil
59
63
  end
@@ -85,11 +89,6 @@ module DEBUGGER__
85
89
  end
86
90
  end
87
91
 
88
- def puts msg
89
- @output.puts msg
90
- @output.flush
91
- end
92
-
93
92
  def minfo tp
94
93
  return "block{}" if tp.event == :b_call
95
94
 
data/lib/debug/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DEBUGGER__
4
- VERSION = "1.7.0"
4
+ VERSION = "1.7.2"
5
5
  end
data/misc/README.md.erb CHANGED
@@ -26,7 +26,7 @@ New debug.rb has several advantages:
26
26
  * Support threads (almost done) and ractors (TODO).
27
27
  * Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
28
28
  * Show parameters on backtrace command.
29
- * Support recording & reply debugging.
29
+ * Support recording & replay debugging.
30
30
 
31
31
  # Installation
32
32
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debug
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-02 00:00:00.000000000 Z
11
+ date: 2023-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: irb