debug 1.7.0 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
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