debug 1.6.2 → 1.7.1
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 +4 -4
- data/CONTRIBUTING.md +20 -8
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +39 -16
- data/Rakefile +0 -0
- data/TODO.md +8 -8
- data/debug.gemspec +1 -1
- data/exe/rdbg +17 -2
- data/ext/debug/debug.c +15 -1
- data/ext/debug/extconf.rb +0 -0
- data/ext/debug/iseq_collector.c +0 -0
- data/lib/debug/abbrev_command.rb +77 -0
- data/lib/debug/breakpoint.rb +17 -11
- data/lib/debug/client.rb +27 -10
- data/lib/debug/color.rb +0 -0
- data/lib/debug/config.rb +34 -16
- data/lib/debug/console.rb +0 -0
- data/lib/debug/frame_info.rb +0 -0
- data/lib/debug/local.rb +16 -10
- data/lib/debug/open.rb +0 -0
- data/lib/debug/open_nonstop.rb +0 -0
- data/lib/debug/prelude.rb +1 -1
- data/lib/debug/server.rb +25 -21
- data/lib/debug/server_cdp.rb +293 -87
- data/lib/debug/server_dap.rb +133 -48
- data/lib/debug/session.rb +390 -208
- data/lib/debug/source_repository.rb +39 -19
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +197 -64
- data/lib/debug/tracer.rb +0 -0
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +7 -3
- data/misc/README.md.erb +11 -5
- metadata +5 -4
@@ -6,6 +6,22 @@ module DEBUGGER__
|
|
6
6
|
class SourceRepository
|
7
7
|
include Color
|
8
8
|
|
9
|
+
def file_src iseq
|
10
|
+
if (path = (iseq.absolute_path || iseq.path)) && File.exist?(path)
|
11
|
+
File.readlines(path, chomp: true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def get iseq
|
16
|
+
return unless iseq
|
17
|
+
|
18
|
+
if CONFIG[:show_evaledsrc]
|
19
|
+
orig_src(iseq) || file_src(iseq)
|
20
|
+
else
|
21
|
+
file_src(iseq) || orig_src(iseq)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
9
25
|
if RubyVM.respond_to? :keep_script_lines
|
10
26
|
# Ruby 3.1 and later
|
11
27
|
RubyVM.keep_script_lines = true
|
@@ -29,17 +45,13 @@ module DEBUGGER__
|
|
29
45
|
end
|
30
46
|
end
|
31
47
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
if
|
36
|
-
lines
|
48
|
+
def orig_src iseq
|
49
|
+
lines = iseq.script_lines&.map(&:chomp)
|
50
|
+
line = iseq.first_line
|
51
|
+
if line > 1
|
52
|
+
lines = [*([''] * (line - 1)), *lines]
|
37
53
|
else
|
38
|
-
|
39
|
-
File.readlines(path, chomp: true)
|
40
|
-
else
|
41
|
-
nil
|
42
|
-
end
|
54
|
+
lines
|
43
55
|
end
|
44
56
|
end
|
45
57
|
|
@@ -63,15 +75,22 @@ module DEBUGGER__
|
|
63
75
|
end
|
64
76
|
|
65
77
|
def add iseq, src
|
66
|
-
|
78
|
+
path = (iseq.absolute_path || iseq.path)
|
79
|
+
|
80
|
+
if path && File.exist?(path)
|
67
81
|
reloaded = @files.has_key? path
|
68
|
-
|
69
|
-
|
70
|
-
|
82
|
+
|
83
|
+
if src
|
84
|
+
add_iseq iseq, src
|
85
|
+
return path, reloaded
|
86
|
+
else
|
87
|
+
add_path path
|
88
|
+
return path, reloaded
|
89
|
+
end
|
90
|
+
else
|
71
91
|
add_iseq iseq, src
|
92
|
+
nil
|
72
93
|
end
|
73
|
-
|
74
|
-
nil
|
75
94
|
end
|
76
95
|
|
77
96
|
private def all_iseq iseq, rs = []
|
@@ -87,7 +106,8 @@ module DEBUGGER__
|
|
87
106
|
if line > 1
|
88
107
|
src = ("\n" * (line - 1)) + src
|
89
108
|
end
|
90
|
-
|
109
|
+
|
110
|
+
si = SrcInfo.new(src.each_line.map{|l| l.chomp})
|
91
111
|
all_iseq(iseq).each{|e|
|
92
112
|
e.instance_variable_set(:@debugger_si, si)
|
93
113
|
e.freeze
|
@@ -102,7 +122,7 @@ module DEBUGGER__
|
|
102
122
|
|
103
123
|
private def get_si iseq
|
104
124
|
return unless iseq
|
105
|
-
|
125
|
+
|
106
126
|
if iseq.instance_variable_defined?(:@debugger_si)
|
107
127
|
iseq.instance_variable_get(:@debugger_si)
|
108
128
|
elsif @files.has_key?(path = (iseq.absolute_path || iseq.path))
|
@@ -112,7 +132,7 @@ module DEBUGGER__
|
|
112
132
|
end
|
113
133
|
end
|
114
134
|
|
115
|
-
def
|
135
|
+
def orig_src iseq
|
116
136
|
if si = get_si(iseq)
|
117
137
|
si.src
|
118
138
|
end
|
data/lib/debug/start.rb
CHANGED
data/lib/debug/thread_client.rb
CHANGED
@@ -18,7 +18,7 @@ module DEBUGGER__
|
|
18
18
|
module SkipPathHelper
|
19
19
|
def skip_path?(path)
|
20
20
|
!path ||
|
21
|
-
|
21
|
+
DEBUGGER__.skip? ||
|
22
22
|
ThreadClient.current.management? ||
|
23
23
|
skip_internal_path?(path) ||
|
24
24
|
skip_config_skip_path?(path)
|
@@ -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
|
|
@@ -291,8 +299,10 @@ module DEBUGGER__
|
|
291
299
|
end
|
292
300
|
|
293
301
|
if event != :pause
|
294
|
-
|
295
|
-
|
302
|
+
unless bp&.skip_src
|
303
|
+
show_src
|
304
|
+
show_frames CONFIG[:show_frames]
|
305
|
+
end
|
296
306
|
|
297
307
|
set_mode :waiting
|
298
308
|
|
@@ -328,11 +338,15 @@ module DEBUGGER__
|
|
328
338
|
@step_tp.disable if @step_tp
|
329
339
|
|
330
340
|
thread = Thread.current
|
341
|
+
subsession_id = SESSION.subsession_id
|
331
342
|
|
332
343
|
if SUPPORT_TARGET_THREAD
|
333
344
|
@step_tp = TracePoint.new(*events){|tp|
|
334
|
-
|
335
|
-
|
345
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
346
|
+
tp.disable
|
347
|
+
next
|
348
|
+
end
|
349
|
+
next if !yield(tp)
|
336
350
|
next if tp.path.start_with?(__dir__)
|
337
351
|
next if tp.path.start_with?('<internal:trace_point>')
|
338
352
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -347,8 +361,11 @@ module DEBUGGER__
|
|
347
361
|
else
|
348
362
|
@step_tp = TracePoint.new(*events){|tp|
|
349
363
|
next if thread != Thread.current
|
350
|
-
|
351
|
-
|
364
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
365
|
+
tp.disable
|
366
|
+
next
|
367
|
+
end
|
368
|
+
next if !yield(tp)
|
352
369
|
next if tp.path.start_with?(__dir__)
|
353
370
|
next if tp.path.start_with?('<internal:trace_point>')
|
354
371
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -384,15 +401,19 @@ module DEBUGGER__
|
|
384
401
|
end
|
385
402
|
end
|
386
403
|
|
387
|
-
def frame_eval_core src, b
|
404
|
+
def frame_eval_core src, b, binding_location: false
|
388
405
|
saved_target_frames = @target_frames
|
389
406
|
saved_current_frame_index = @current_frame_index
|
390
407
|
|
391
408
|
if b
|
392
|
-
|
409
|
+
file, lineno = b.source_location
|
393
410
|
|
394
411
|
tp_allow_reentry do
|
395
|
-
|
412
|
+
if binding_location
|
413
|
+
b.eval(src, file, lineno)
|
414
|
+
else
|
415
|
+
b.eval(src, "(rdbg)/#{file}")
|
416
|
+
end
|
396
417
|
end
|
397
418
|
else
|
398
419
|
frame_self = current_frame.self
|
@@ -411,16 +432,16 @@ module DEBUGGER__
|
|
411
432
|
[:return_value, "_return"],
|
412
433
|
]
|
413
434
|
|
414
|
-
def frame_eval src, re_raise: false
|
435
|
+
def frame_eval src, re_raise: false, binding_location: false
|
415
436
|
@success_last_eval = false
|
416
437
|
|
417
|
-
b = current_frame
|
438
|
+
b = current_frame&.eval_binding || TOPLEVEL_BINDING
|
418
439
|
|
419
440
|
special_local_variables current_frame do |name, var|
|
420
441
|
b.local_variable_set(name, var) if /\%/ !~ name
|
421
442
|
end
|
422
443
|
|
423
|
-
result = frame_eval_core(src, b)
|
444
|
+
result = frame_eval_core(src, b, binding_location: binding_location)
|
424
445
|
|
425
446
|
@success_last_eval = true
|
426
447
|
result
|
@@ -482,19 +503,28 @@ module DEBUGGER__
|
|
482
503
|
exit!
|
483
504
|
end
|
484
505
|
|
485
|
-
def show_src(frame_index: @current_frame_index, update_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
506
|
+
def show_src(frame_index: @current_frame_index, update_line: false, ignore_show_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
486
507
|
if frame = get_frame(frame_index)
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
frame.show_line = end_line
|
508
|
+
begin
|
509
|
+
if ignore_show_line
|
510
|
+
prev_show_line = frame.show_line
|
511
|
+
frame.show_line = nil
|
492
512
|
end
|
493
513
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
514
|
+
start_line, end_line, lines = *get_src(frame, max_lines: max_lines, **options)
|
515
|
+
|
516
|
+
if start_line
|
517
|
+
if update_line
|
518
|
+
frame.show_line = end_line
|
519
|
+
end
|
520
|
+
|
521
|
+
puts "[#{start_line+1}, #{end_line}] in #{frame.pretty_path}" if !update_line && max_lines != 1
|
522
|
+
puts lines[start_line...end_line]
|
523
|
+
else
|
524
|
+
puts "# No sourcefile available for #{frame.path}"
|
525
|
+
end
|
526
|
+
ensure
|
527
|
+
frame.show_line = prev_show_line if prev_show_line
|
498
528
|
end
|
499
529
|
end
|
500
530
|
end
|
@@ -546,48 +576,76 @@ module DEBUGGER__
|
|
546
576
|
end
|
547
577
|
end
|
548
578
|
|
549
|
-
def show_ivars pat
|
550
|
-
if
|
551
|
-
|
552
|
-
|
579
|
+
def show_ivars pat, expr = nil
|
580
|
+
if expr && !expr.empty?
|
581
|
+
_self = frame_eval(expr);
|
582
|
+
elsif _self = current_frame&.self
|
583
|
+
else
|
584
|
+
_self = nil
|
585
|
+
end
|
586
|
+
|
587
|
+
if _self
|
588
|
+
M_INSTANCE_VARIABLES.bind_call(_self).sort.each{|iv|
|
589
|
+
value = M_INSTANCE_VARIABLE_GET.bind_call(_self, iv)
|
553
590
|
puts_variable_info iv, value, pat
|
554
591
|
}
|
555
592
|
end
|
556
593
|
end
|
557
594
|
|
558
|
-
def
|
559
|
-
|
595
|
+
def iter_consts c, names = {}
|
596
|
+
c.constants(false).sort.each{|name|
|
597
|
+
next if names.has_key? name
|
598
|
+
names[name] = nil
|
599
|
+
begin
|
600
|
+
value = c.const_get(name)
|
601
|
+
rescue Exception => e
|
602
|
+
value = e
|
603
|
+
end
|
604
|
+
yield name, value
|
605
|
+
}
|
606
|
+
end
|
607
|
+
|
608
|
+
def get_consts expr = nil, only_self: false, &block
|
609
|
+
if expr && !expr.empty?
|
610
|
+
_self = frame_eval(expr)
|
611
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
612
|
+
iter_consts _self, &block
|
613
|
+
return
|
614
|
+
else
|
615
|
+
raise "#{_self.inspect} (by #{expr}) is not a Module."
|
616
|
+
end
|
617
|
+
elsif _self = current_frame&.self
|
560
618
|
cs = {}
|
561
|
-
if M_KIND_OF_P.bind_call(
|
562
|
-
cs[
|
619
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
620
|
+
cs[_self] = :self
|
563
621
|
else
|
564
|
-
|
565
|
-
cs[
|
622
|
+
_self = M_CLASS.bind_call(_self)
|
623
|
+
cs[_self] = :self unless only_self
|
566
624
|
end
|
567
625
|
|
568
626
|
unless only_self
|
569
|
-
|
627
|
+
_self.ancestors.each{|c| break if c == Object; cs[c] = :ancestors}
|
570
628
|
if b = current_frame&.binding
|
571
|
-
b.eval('Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c}
|
629
|
+
b.eval('::Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c}
|
572
630
|
end
|
573
631
|
end
|
574
632
|
|
575
633
|
names = {}
|
576
634
|
|
577
635
|
cs.each{|c, _|
|
578
|
-
c
|
579
|
-
next if names.has_key? name
|
580
|
-
names[name] = nil
|
581
|
-
value = c.const_get(name)
|
582
|
-
puts_variable_info name, value, pat
|
583
|
-
}
|
636
|
+
iter_consts c, names, &block
|
584
637
|
}
|
585
638
|
end
|
586
639
|
end
|
587
640
|
|
588
|
-
|
641
|
+
def show_consts pat, expr = nil, only_self: false
|
642
|
+
get_consts expr, only_self: only_self do |name, value|
|
643
|
+
puts_variable_info name, value, pat
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
589
647
|
def show_globals pat
|
590
|
-
|
648
|
+
safe_global_variables.sort.each{|name|
|
591
649
|
next if SKIP_GLOBAL_LIST.include? name
|
592
650
|
|
593
651
|
value = eval(name.to_s)
|
@@ -643,7 +701,8 @@ module DEBUGGER__
|
|
643
701
|
if editor = (ENV['RUBY_DEBUG_EDITOR'] || ENV['EDITOR'])
|
644
702
|
puts "command: #{editor}"
|
645
703
|
puts " path: #{path}"
|
646
|
-
|
704
|
+
require 'shellwords'
|
705
|
+
system(*Shellwords.split(editor), path)
|
647
706
|
else
|
648
707
|
puts "can not find editor setting: ENV['RUBY_DEBUG_EDITOR'] or ENV['EDITOR']"
|
649
708
|
end
|
@@ -758,7 +817,7 @@ module DEBUGGER__
|
|
758
817
|
case args.first
|
759
818
|
when :method
|
760
819
|
klass_name, op, method_name, cond, cmd, path = args[1..]
|
761
|
-
bp = MethodBreakpoint.new(current_frame
|
820
|
+
bp = MethodBreakpoint.new(current_frame&.eval_binding || TOPLEVEL_BINDING, klass_name, op, method_name, cond: cond, command: cmd, path: path)
|
762
821
|
begin
|
763
822
|
bp.enable
|
764
823
|
rescue NameError => e
|
@@ -814,6 +873,7 @@ module DEBUGGER__
|
|
814
873
|
set_mode :waiting if !waiting?
|
815
874
|
cmds = @q_cmd.pop
|
816
875
|
# pp [self, cmds: cmds]
|
876
|
+
|
817
877
|
break unless cmds
|
818
878
|
ensure
|
819
879
|
set_mode :running
|
@@ -831,8 +891,9 @@ module DEBUGGER__
|
|
831
891
|
|
832
892
|
case step_type
|
833
893
|
when :in
|
894
|
+
iter = iter || 1
|
834
895
|
if @recorder&.replaying?
|
835
|
-
@recorder.step_forward
|
896
|
+
@recorder.step_forward iter
|
836
897
|
raise SuspendReplay
|
837
898
|
else
|
838
899
|
step_tp iter do
|
@@ -845,6 +906,7 @@ module DEBUGGER__
|
|
845
906
|
frame = @target_frames.first
|
846
907
|
path = frame.location.absolute_path || "!eval:#{frame.path}"
|
847
908
|
line = frame.location.lineno
|
909
|
+
label = frame.location.base_label
|
848
910
|
|
849
911
|
if frame.iseq
|
850
912
|
frame.iseq.traceable_lines_norec(lines = {})
|
@@ -856,35 +918,89 @@ module DEBUGGER__
|
|
856
918
|
|
857
919
|
depth = @target_frames.first.frame_depth
|
858
920
|
|
859
|
-
step_tp iter do
|
921
|
+
step_tp iter do |tp|
|
860
922
|
loc = caller_locations(2, 1).first
|
861
923
|
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
924
|
+
loc_label = loc.base_label
|
925
|
+
loc_depth = DEBUGGER__.frame_depth - 3
|
862
926
|
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
927
|
+
case
|
928
|
+
when loc_depth == depth && loc_label == label
|
929
|
+
true
|
930
|
+
when loc_depth < depth
|
931
|
+
# lower stack depth
|
932
|
+
true
|
933
|
+
when (next_line &&
|
934
|
+
loc_path == path &&
|
935
|
+
(loc_lineno = loc.lineno) > line &&
|
936
|
+
loc_lineno <= next_line)
|
937
|
+
# different frame (maybe block) but the line is before next_line
|
938
|
+
true
|
939
|
+
end
|
870
940
|
end
|
871
941
|
break
|
872
942
|
|
873
943
|
when :finish
|
874
944
|
finish_frames = (iter || 1) - 1
|
875
|
-
|
945
|
+
frame = @target_frames.first
|
946
|
+
goal_depth = frame.frame_depth - finish_frames - (frame.has_return_value ? 1 : 0)
|
876
947
|
|
877
948
|
step_tp nil, [:return, :b_return] do
|
878
949
|
DEBUGGER__.frame_depth - 3 <= goal_depth ? true : false
|
879
950
|
end
|
880
951
|
break
|
881
952
|
|
953
|
+
when :until
|
954
|
+
location = iter&.strip
|
955
|
+
frame = @target_frames.first
|
956
|
+
depth = frame.frame_depth - (frame.has_return_value ? 1 : 0)
|
957
|
+
target_location_label = frame.location.base_label
|
958
|
+
|
959
|
+
case location
|
960
|
+
when nil, /\A(?:(.+):)?(\d+)\z/
|
961
|
+
no_loc = !location
|
962
|
+
file = $1 || frame.location.path
|
963
|
+
line = ($2 || frame.location.lineno + 1).to_i
|
964
|
+
|
965
|
+
step_tp nil, [:line, :return] do |tp|
|
966
|
+
if tp.event == :line
|
967
|
+
next false if no_loc && depth < DEBUGGER__.frame_depth - 3
|
968
|
+
next false unless tp.path.end_with?(file)
|
969
|
+
next false unless tp.lineno >= line
|
970
|
+
true
|
971
|
+
else
|
972
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
973
|
+
caller_locations(2, 1).first.label == target_location_label
|
974
|
+
# TODO: imcomplete condition
|
975
|
+
end
|
976
|
+
end
|
977
|
+
else
|
978
|
+
pat = location
|
979
|
+
if /\A\/(.+)\/\z/ =~ pat
|
980
|
+
pat = Regexp.new($1)
|
981
|
+
end
|
982
|
+
|
983
|
+
step_tp nil, [:call, :c_call, :return] do |tp|
|
984
|
+
case tp.event
|
985
|
+
when :call, :c_call
|
986
|
+
true if pat === tp.callee_id.to_s
|
987
|
+
else # :return, :b_return
|
988
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
989
|
+
caller_locations(2, 1).first.label == target_location_label
|
990
|
+
# TODO: imcomplete condition
|
991
|
+
end
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
break
|
996
|
+
|
882
997
|
when :back
|
998
|
+
iter = iter || 1
|
883
999
|
if @recorder&.can_step_back?
|
884
1000
|
unless @recorder.backup_frames
|
885
1001
|
@recorder.backup_frames = @target_frames
|
886
1002
|
end
|
887
|
-
@recorder.step_back
|
1003
|
+
@recorder.step_back iter
|
888
1004
|
raise SuspendReplay
|
889
1005
|
else
|
890
1006
|
puts "Can not step back more."
|
@@ -922,8 +1038,9 @@ module DEBUGGER__
|
|
922
1038
|
when :call
|
923
1039
|
result = frame_eval(eval_src)
|
924
1040
|
when :irb
|
1041
|
+
require 'irb' # prelude's binding.irb doesn't have show_code option
|
925
1042
|
begin
|
926
|
-
result = frame_eval('binding.irb')
|
1043
|
+
result = frame_eval('binding.irb(show_code: false)', binding_location: true)
|
927
1044
|
ensure
|
928
1045
|
# workaround: https://github.com/ruby/debug/issues/308
|
929
1046
|
Reline.prompt_proc = nil if defined? Reline
|
@@ -988,6 +1105,10 @@ module DEBUGGER__
|
|
988
1105
|
when :list
|
989
1106
|
show_src(update_line: true, **(args.first || {}))
|
990
1107
|
|
1108
|
+
when :whereami
|
1109
|
+
show_src ignore_show_line: true
|
1110
|
+
show_frames CONFIG[:show_frames]
|
1111
|
+
|
991
1112
|
when :edit
|
992
1113
|
show_by_editor(args.first)
|
993
1114
|
|
@@ -1003,11 +1124,13 @@ module DEBUGGER__
|
|
1003
1124
|
|
1004
1125
|
when :ivars
|
1005
1126
|
pat = args.shift
|
1006
|
-
|
1127
|
+
expr = args.shift
|
1128
|
+
show_ivars pat, expr
|
1007
1129
|
|
1008
1130
|
when :consts
|
1009
1131
|
pat = args.shift
|
1010
|
-
|
1132
|
+
expr = args.shift
|
1133
|
+
show_consts pat, expr
|
1011
1134
|
|
1012
1135
|
when :globals
|
1013
1136
|
pat = args.shift
|
@@ -1093,6 +1216,8 @@ module DEBUGGER__
|
|
1093
1216
|
end
|
1094
1217
|
event! :result, nil
|
1095
1218
|
|
1219
|
+
when :quit
|
1220
|
+
sleep # wait for SystemExit
|
1096
1221
|
when :dap
|
1097
1222
|
process_dap args
|
1098
1223
|
when :cdp
|
@@ -1107,6 +1232,8 @@ module DEBUGGER__
|
|
1107
1232
|
rescue Exception => e
|
1108
1233
|
pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
1109
1234
|
raise
|
1235
|
+
ensure
|
1236
|
+
@returning = false
|
1110
1237
|
end
|
1111
1238
|
|
1112
1239
|
def debug_event(ev, args)
|
@@ -1187,12 +1314,18 @@ module DEBUGGER__
|
|
1187
1314
|
@tp_recorder.enabled?
|
1188
1315
|
end
|
1189
1316
|
|
1190
|
-
def step_back
|
1191
|
-
@index +=
|
1317
|
+
def step_back iter
|
1318
|
+
@index += iter
|
1319
|
+
if @index > @log.size
|
1320
|
+
@index = @log.size
|
1321
|
+
end
|
1192
1322
|
end
|
1193
1323
|
|
1194
|
-
def step_forward
|
1195
|
-
@index -=
|
1324
|
+
def step_forward iter
|
1325
|
+
@index -= iter
|
1326
|
+
if @index < 0
|
1327
|
+
@index = 0
|
1328
|
+
end
|
1196
1329
|
end
|
1197
1330
|
|
1198
1331
|
def step_reset
|
data/lib/debug/tracer.rb
CHANGED
File without changes
|
data/lib/debug/version.rb
CHANGED
data/lib/debug.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
if ENV['RUBY_DEBUG_LAZY']
|
4
|
+
require_relative 'debug/prelude'
|
5
|
+
else
|
6
|
+
require_relative 'debug/session'
|
7
|
+
return unless defined?(DEBUGGER__)
|
8
|
+
DEBUGGER__::start no_sigint_hook: true, nonstop: true
|
9
|
+
end
|
data/misc/README.md.erb
CHANGED
@@ -438,12 +438,12 @@ $ rdbg target.rb --open=chrome
|
|
438
438
|
DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:43633)
|
439
439
|
DEBUGGER: With Chrome browser, type the following URL in the address-bar:
|
440
440
|
|
441
|
-
devtools://devtools/bundled/inspector.html?ws=127.0.0.1:
|
441
|
+
devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=127.0.0.1:57231/b32a55cd-2eb5-4c5c-87d8-b3dfc59d80ef
|
442
442
|
|
443
443
|
DEBUGGER: wait for debugger connection...
|
444
444
|
```
|
445
445
|
|
446
|
-
Type `devtools://devtools/bundled/inspector.html?ws=127.0.0.1:
|
446
|
+
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.
|
447
447
|
|
448
448
|
Also `open chrome` command works like `open vscode`.
|
449
449
|
|
@@ -498,7 +498,8 @@ There are additional features:
|
|
498
498
|
* `<expr>` without debug command is almost same as `pp <expr>`.
|
499
499
|
* If the input line `<expr>` does *NOT* start with any debug command, the line `<expr>` 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`.
|
500
500
|
* If `<expr>` 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.
|
501
|
-
*
|
501
|
+
* So the author (Koichi Sasada) recommends to use `p`, `pp` or `eval` command to evaluate the Ruby expression everytime.
|
502
|
+
* `Enter` without any input repeats the last command (useful when repeating `step`s) for some commands.
|
502
503
|
* `Ctrl-D` is equal to `quit` command.
|
503
504
|
* [debug command compare sheet - Google Sheets](https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit?usp=sharing)
|
504
505
|
|
@@ -567,11 +568,11 @@ It is useful if you only want to call a debug command and don't want to stop the
|
|
567
568
|
```
|
568
569
|
def initialize
|
569
570
|
@a = 1
|
570
|
-
binding.b do: 'watch @a'
|
571
|
+
binding.b do: 'info \n watch @a'
|
571
572
|
end
|
572
573
|
```
|
573
574
|
|
574
|
-
On this case, register a watch breakpoint for `@a` and continue to run.
|
575
|
+
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.
|
575
576
|
|
576
577
|
If `pre: 'command'` is specified, the debugger suspends the program and run the `command` as a debug command, and keep suspend.
|
577
578
|
It is useful if you have operations before suspend.
|
@@ -591,6 +592,11 @@ On this case, you can see the result of `bar()` every time you stop there.
|
|
591
592
|
<%= `exe/rdbg --help` %>
|
592
593
|
```
|
593
594
|
|
595
|
+
# Additional Resources
|
596
|
+
|
597
|
+
- [From byebug to ruby/debug](https://st0012.dev/from-byebug-to-ruby-debug) by Stan Lo - A migration guide for `byebug` users.
|
598
|
+
- [ruby/debug cheatsheet](https://st0012.dev/ruby-debug-cheatsheet) by Stan Lo
|
599
|
+
|
594
600
|
# Contributing
|
595
601
|
|
596
602
|
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/debug.
|