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