debug 1.6.3 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +19 -7
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +37 -14
- data/Rakefile +0 -0
- data/TODO.md +0 -0
- data/debug.gemspec +1 -1
- data/exe/rdbg +1 -1
- 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 +26 -9
- 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 +0 -0
- data/lib/debug/server.rb +25 -21
- data/lib/debug/server_cdp.rb +281 -80
- data/lib/debug/server_dap.rb +109 -37
- data/lib/debug/session.rb +384 -204
- data/lib/debug/source_repository.rb +39 -19
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +186 -60
- 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 +9 -3
- 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)
|
@@ -291,8 +291,10 @@ module DEBUGGER__
|
|
291
291
|
end
|
292
292
|
|
293
293
|
if event != :pause
|
294
|
-
|
295
|
-
|
294
|
+
unless bp&.skip_src
|
295
|
+
show_src
|
296
|
+
show_frames CONFIG[:show_frames]
|
297
|
+
end
|
296
298
|
|
297
299
|
set_mode :waiting
|
298
300
|
|
@@ -328,11 +330,15 @@ module DEBUGGER__
|
|
328
330
|
@step_tp.disable if @step_tp
|
329
331
|
|
330
332
|
thread = Thread.current
|
333
|
+
subsession_id = SESSION.subsession_id
|
331
334
|
|
332
335
|
if SUPPORT_TARGET_THREAD
|
333
336
|
@step_tp = TracePoint.new(*events){|tp|
|
334
|
-
|
335
|
-
|
337
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
338
|
+
tp.disable
|
339
|
+
next
|
340
|
+
end
|
341
|
+
next if !yield(tp)
|
336
342
|
next if tp.path.start_with?(__dir__)
|
337
343
|
next if tp.path.start_with?('<internal:trace_point>')
|
338
344
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -347,8 +353,11 @@ module DEBUGGER__
|
|
347
353
|
else
|
348
354
|
@step_tp = TracePoint.new(*events){|tp|
|
349
355
|
next if thread != Thread.current
|
350
|
-
|
351
|
-
|
356
|
+
if SESSION.stop_stepping? tp.path, tp.lineno, subsession_id
|
357
|
+
tp.disable
|
358
|
+
next
|
359
|
+
end
|
360
|
+
next if !yield(tp)
|
352
361
|
next if tp.path.start_with?(__dir__)
|
353
362
|
next if tp.path.start_with?('<internal:trace_point>')
|
354
363
|
next unless File.exist?(tp.path) if CONFIG[:skip_nosrc]
|
@@ -384,15 +393,19 @@ module DEBUGGER__
|
|
384
393
|
end
|
385
394
|
end
|
386
395
|
|
387
|
-
def frame_eval_core src, b
|
396
|
+
def frame_eval_core src, b, binding_location: false
|
388
397
|
saved_target_frames = @target_frames
|
389
398
|
saved_current_frame_index = @current_frame_index
|
390
399
|
|
391
400
|
if b
|
392
|
-
|
401
|
+
file, lineno = b.source_location
|
393
402
|
|
394
403
|
tp_allow_reentry do
|
395
|
-
|
404
|
+
if binding_location
|
405
|
+
b.eval(src, file, lineno)
|
406
|
+
else
|
407
|
+
b.eval(src, "(rdbg)/#{file}")
|
408
|
+
end
|
396
409
|
end
|
397
410
|
else
|
398
411
|
frame_self = current_frame.self
|
@@ -411,16 +424,16 @@ module DEBUGGER__
|
|
411
424
|
[:return_value, "_return"],
|
412
425
|
]
|
413
426
|
|
414
|
-
def frame_eval src, re_raise: false
|
427
|
+
def frame_eval src, re_raise: false, binding_location: false
|
415
428
|
@success_last_eval = false
|
416
429
|
|
417
|
-
b = current_frame
|
430
|
+
b = current_frame&.eval_binding || TOPLEVEL_BINDING
|
418
431
|
|
419
432
|
special_local_variables current_frame do |name, var|
|
420
433
|
b.local_variable_set(name, var) if /\%/ !~ name
|
421
434
|
end
|
422
435
|
|
423
|
-
result = frame_eval_core(src, b)
|
436
|
+
result = frame_eval_core(src, b, binding_location: binding_location)
|
424
437
|
|
425
438
|
@success_last_eval = true
|
426
439
|
result
|
@@ -482,19 +495,28 @@ module DEBUGGER__
|
|
482
495
|
exit!
|
483
496
|
end
|
484
497
|
|
485
|
-
def show_src(frame_index: @current_frame_index, update_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
498
|
+
def show_src(frame_index: @current_frame_index, update_line: false, ignore_show_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
486
499
|
if frame = get_frame(frame_index)
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
frame.show_line = end_line
|
500
|
+
begin
|
501
|
+
if ignore_show_line
|
502
|
+
prev_show_line = frame.show_line
|
503
|
+
frame.show_line = nil
|
492
504
|
end
|
493
505
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
506
|
+
start_line, end_line, lines = *get_src(frame, max_lines: max_lines, **options)
|
507
|
+
|
508
|
+
if start_line
|
509
|
+
if update_line
|
510
|
+
frame.show_line = end_line
|
511
|
+
end
|
512
|
+
|
513
|
+
puts "[#{start_line+1}, #{end_line}] in #{frame.pretty_path}" if !update_line && max_lines != 1
|
514
|
+
puts lines[start_line...end_line]
|
515
|
+
else
|
516
|
+
puts "# No sourcefile available for #{frame.path}"
|
517
|
+
end
|
518
|
+
ensure
|
519
|
+
frame.show_line = prev_show_line if prev_show_line
|
498
520
|
end
|
499
521
|
end
|
500
522
|
end
|
@@ -546,27 +568,55 @@ module DEBUGGER__
|
|
546
568
|
end
|
547
569
|
end
|
548
570
|
|
549
|
-
def show_ivars pat
|
550
|
-
if
|
551
|
-
|
552
|
-
|
571
|
+
def show_ivars pat, expr = nil
|
572
|
+
if expr && !expr.empty?
|
573
|
+
_self = frame_eval(expr);
|
574
|
+
elsif _self = current_frame&.self
|
575
|
+
else
|
576
|
+
_self = nil
|
577
|
+
end
|
578
|
+
|
579
|
+
if _self
|
580
|
+
M_INSTANCE_VARIABLES.bind_call(_self).sort.each{|iv|
|
581
|
+
value = M_INSTANCE_VARIABLE_GET.bind_call(_self, iv)
|
553
582
|
puts_variable_info iv, value, pat
|
554
583
|
}
|
555
584
|
end
|
556
585
|
end
|
557
586
|
|
558
|
-
def
|
559
|
-
|
587
|
+
def iter_consts c, names = {}
|
588
|
+
c.constants(false).sort.each{|name|
|
589
|
+
next if names.has_key? name
|
590
|
+
names[name] = nil
|
591
|
+
begin
|
592
|
+
value = c.const_get(name)
|
593
|
+
rescue Exception => e
|
594
|
+
value = e
|
595
|
+
end
|
596
|
+
yield name, value
|
597
|
+
}
|
598
|
+
end
|
599
|
+
|
600
|
+
def get_consts expr = nil, only_self: false, &block
|
601
|
+
if expr && !expr.empty?
|
602
|
+
_self = frame_eval(expr)
|
603
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
604
|
+
iter_consts _self, &block
|
605
|
+
return
|
606
|
+
else
|
607
|
+
raise "#{_self.inspect} (by #{expr}) is not a Module."
|
608
|
+
end
|
609
|
+
elsif _self = current_frame&.self
|
560
610
|
cs = {}
|
561
|
-
if M_KIND_OF_P.bind_call(
|
562
|
-
cs[
|
611
|
+
if M_KIND_OF_P.bind_call(_self, Module)
|
612
|
+
cs[_self] = :self
|
563
613
|
else
|
564
|
-
|
565
|
-
cs[
|
614
|
+
_self = M_CLASS.bind_call(_self)
|
615
|
+
cs[_self] = :self unless only_self
|
566
616
|
end
|
567
617
|
|
568
618
|
unless only_self
|
569
|
-
|
619
|
+
_self.ancestors.each{|c| break if c == Object; cs[c] = :ancestors}
|
570
620
|
if b = current_frame&.binding
|
571
621
|
b.eval('::Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c}
|
572
622
|
end
|
@@ -575,16 +625,17 @@ module DEBUGGER__
|
|
575
625
|
names = {}
|
576
626
|
|
577
627
|
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
|
-
}
|
628
|
+
iter_consts c, names, &block
|
584
629
|
}
|
585
630
|
end
|
586
631
|
end
|
587
632
|
|
633
|
+
def show_consts pat, expr = nil, only_self: false
|
634
|
+
get_consts expr, only_self: only_self do |name, value|
|
635
|
+
puts_variable_info name, value, pat
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
588
639
|
SKIP_GLOBAL_LIST = %i[$= $KCODE $-K $SAFE].freeze
|
589
640
|
def show_globals pat
|
590
641
|
global_variables.sort.each{|name|
|
@@ -643,7 +694,8 @@ module DEBUGGER__
|
|
643
694
|
if editor = (ENV['RUBY_DEBUG_EDITOR'] || ENV['EDITOR'])
|
644
695
|
puts "command: #{editor}"
|
645
696
|
puts " path: #{path}"
|
646
|
-
|
697
|
+
require 'shellwords'
|
698
|
+
system(*Shellwords.split(editor), path)
|
647
699
|
else
|
648
700
|
puts "can not find editor setting: ENV['RUBY_DEBUG_EDITOR'] or ENV['EDITOR']"
|
649
701
|
end
|
@@ -758,7 +810,7 @@ module DEBUGGER__
|
|
758
810
|
case args.first
|
759
811
|
when :method
|
760
812
|
klass_name, op, method_name, cond, cmd, path = args[1..]
|
761
|
-
bp = MethodBreakpoint.new(current_frame
|
813
|
+
bp = MethodBreakpoint.new(current_frame&.eval_binding || TOPLEVEL_BINDING, klass_name, op, method_name, cond: cond, command: cmd, path: path)
|
762
814
|
begin
|
763
815
|
bp.enable
|
764
816
|
rescue NameError => e
|
@@ -814,6 +866,7 @@ module DEBUGGER__
|
|
814
866
|
set_mode :waiting if !waiting?
|
815
867
|
cmds = @q_cmd.pop
|
816
868
|
# pp [self, cmds: cmds]
|
869
|
+
|
817
870
|
break unless cmds
|
818
871
|
ensure
|
819
872
|
set_mode :running
|
@@ -831,8 +884,9 @@ module DEBUGGER__
|
|
831
884
|
|
832
885
|
case step_type
|
833
886
|
when :in
|
887
|
+
iter = iter || 1
|
834
888
|
if @recorder&.replaying?
|
835
|
-
@recorder.step_forward
|
889
|
+
@recorder.step_forward iter
|
836
890
|
raise SuspendReplay
|
837
891
|
else
|
838
892
|
step_tp iter do
|
@@ -845,6 +899,7 @@ module DEBUGGER__
|
|
845
899
|
frame = @target_frames.first
|
846
900
|
path = frame.location.absolute_path || "!eval:#{frame.path}"
|
847
901
|
line = frame.location.lineno
|
902
|
+
label = frame.location.base_label
|
848
903
|
|
849
904
|
if frame.iseq
|
850
905
|
frame.iseq.traceable_lines_norec(lines = {})
|
@@ -856,35 +911,89 @@ module DEBUGGER__
|
|
856
911
|
|
857
912
|
depth = @target_frames.first.frame_depth
|
858
913
|
|
859
|
-
step_tp iter do
|
914
|
+
step_tp iter do |tp|
|
860
915
|
loc = caller_locations(2, 1).first
|
861
916
|
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
917
|
+
loc_label = loc.base_label
|
918
|
+
loc_depth = DEBUGGER__.frame_depth - 3
|
862
919
|
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
920
|
+
case
|
921
|
+
when loc_depth == depth && loc_label == label
|
922
|
+
true
|
923
|
+
when loc_depth < depth
|
924
|
+
# lower stack depth
|
925
|
+
true
|
926
|
+
when (next_line &&
|
927
|
+
loc_path == path &&
|
928
|
+
(loc_lineno = loc.lineno) > line &&
|
929
|
+
loc_lineno <= next_line)
|
930
|
+
# different frame (maybe block) but the line is before next_line
|
931
|
+
true
|
932
|
+
end
|
870
933
|
end
|
871
934
|
break
|
872
935
|
|
873
936
|
when :finish
|
874
937
|
finish_frames = (iter || 1) - 1
|
875
|
-
|
938
|
+
frame = @target_frames.first
|
939
|
+
goal_depth = frame.frame_depth - finish_frames - (frame.has_return_value ? 1 : 0)
|
876
940
|
|
877
941
|
step_tp nil, [:return, :b_return] do
|
878
942
|
DEBUGGER__.frame_depth - 3 <= goal_depth ? true : false
|
879
943
|
end
|
880
944
|
break
|
881
945
|
|
946
|
+
when :until
|
947
|
+
location = iter&.strip
|
948
|
+
frame = @target_frames.first
|
949
|
+
depth = frame.frame_depth - (frame.has_return_value ? 1 : 0)
|
950
|
+
target_location_label = frame.location.base_label
|
951
|
+
|
952
|
+
case location
|
953
|
+
when nil, /\A(?:(.+):)?(\d+)\z/
|
954
|
+
no_loc = !location
|
955
|
+
file = $1 || frame.location.path
|
956
|
+
line = ($2 || frame.location.lineno + 1).to_i
|
957
|
+
|
958
|
+
step_tp nil, [:line, :return] do |tp|
|
959
|
+
if tp.event == :line
|
960
|
+
next false if no_loc && depth < DEBUGGER__.frame_depth - 3
|
961
|
+
next false unless tp.path.end_with?(file)
|
962
|
+
next false unless tp.lineno >= line
|
963
|
+
true
|
964
|
+
else
|
965
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
966
|
+
caller_locations(2, 1).first.label == target_location_label
|
967
|
+
# TODO: imcomplete condition
|
968
|
+
end
|
969
|
+
end
|
970
|
+
else
|
971
|
+
pat = location
|
972
|
+
if /\A\/(.+)\/\z/ =~ pat
|
973
|
+
pat = Regexp.new($1)
|
974
|
+
end
|
975
|
+
|
976
|
+
step_tp nil, [:call, :c_call, :return] do |tp|
|
977
|
+
case tp.event
|
978
|
+
when :call, :c_call
|
979
|
+
true if pat === tp.callee_id.to_s
|
980
|
+
else # :return, :b_return
|
981
|
+
true if depth >= DEBUGGER__.frame_depth - 3 &&
|
982
|
+
caller_locations(2, 1).first.label == target_location_label
|
983
|
+
# TODO: imcomplete condition
|
984
|
+
end
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
break
|
989
|
+
|
882
990
|
when :back
|
991
|
+
iter = iter || 1
|
883
992
|
if @recorder&.can_step_back?
|
884
993
|
unless @recorder.backup_frames
|
885
994
|
@recorder.backup_frames = @target_frames
|
886
995
|
end
|
887
|
-
@recorder.step_back
|
996
|
+
@recorder.step_back iter
|
888
997
|
raise SuspendReplay
|
889
998
|
else
|
890
999
|
puts "Can not step back more."
|
@@ -922,8 +1031,9 @@ module DEBUGGER__
|
|
922
1031
|
when :call
|
923
1032
|
result = frame_eval(eval_src)
|
924
1033
|
when :irb
|
1034
|
+
require 'irb' # prelude's binding.irb doesn't have show_code option
|
925
1035
|
begin
|
926
|
-
result = frame_eval('binding.irb')
|
1036
|
+
result = frame_eval('binding.irb(show_code: false)', binding_location: true)
|
927
1037
|
ensure
|
928
1038
|
# workaround: https://github.com/ruby/debug/issues/308
|
929
1039
|
Reline.prompt_proc = nil if defined? Reline
|
@@ -988,6 +1098,10 @@ module DEBUGGER__
|
|
988
1098
|
when :list
|
989
1099
|
show_src(update_line: true, **(args.first || {}))
|
990
1100
|
|
1101
|
+
when :whereami
|
1102
|
+
show_src ignore_show_line: true
|
1103
|
+
show_frames CONFIG[:show_frames]
|
1104
|
+
|
991
1105
|
when :edit
|
992
1106
|
show_by_editor(args.first)
|
993
1107
|
|
@@ -1003,11 +1117,13 @@ module DEBUGGER__
|
|
1003
1117
|
|
1004
1118
|
when :ivars
|
1005
1119
|
pat = args.shift
|
1006
|
-
|
1120
|
+
expr = args.shift
|
1121
|
+
show_ivars pat, expr
|
1007
1122
|
|
1008
1123
|
when :consts
|
1009
1124
|
pat = args.shift
|
1010
|
-
|
1125
|
+
expr = args.shift
|
1126
|
+
show_consts pat, expr
|
1011
1127
|
|
1012
1128
|
when :globals
|
1013
1129
|
pat = args.shift
|
@@ -1093,6 +1209,8 @@ module DEBUGGER__
|
|
1093
1209
|
end
|
1094
1210
|
event! :result, nil
|
1095
1211
|
|
1212
|
+
when :quit
|
1213
|
+
sleep # wait for SystemExit
|
1096
1214
|
when :dap
|
1097
1215
|
process_dap args
|
1098
1216
|
when :cdp
|
@@ -1107,6 +1225,8 @@ module DEBUGGER__
|
|
1107
1225
|
rescue Exception => e
|
1108
1226
|
pp ["DEBUGGER Exception: #{__FILE__}:#{__LINE__}", e, e.backtrace]
|
1109
1227
|
raise
|
1228
|
+
ensure
|
1229
|
+
@returning = false
|
1110
1230
|
end
|
1111
1231
|
|
1112
1232
|
def debug_event(ev, args)
|
@@ -1187,12 +1307,18 @@ module DEBUGGER__
|
|
1187
1307
|
@tp_recorder.enabled?
|
1188
1308
|
end
|
1189
1309
|
|
1190
|
-
def step_back
|
1191
|
-
@index +=
|
1310
|
+
def step_back iter
|
1311
|
+
@index += iter
|
1312
|
+
if @index > @log.size
|
1313
|
+
@index = @log.size
|
1314
|
+
end
|
1192
1315
|
end
|
1193
1316
|
|
1194
|
-
def step_forward
|
1195
|
-
@index -=
|
1317
|
+
def step_forward iter
|
1318
|
+
@index -= iter
|
1319
|
+
if @index < 0
|
1320
|
+
@index = 0
|
1321
|
+
end
|
1196
1322
|
end
|
1197
1323
|
|
1198
1324
|
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
@@ -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.
|
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.
|
4
|
+
version: 1.7.0
|
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-
|
11
|
+
date: 2022-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.5.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.5.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: reline
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- ext/debug/extconf.rb
|
61
61
|
- ext/debug/iseq_collector.c
|
62
62
|
- lib/debug.rb
|
63
|
+
- lib/debug/abbrev_command.rb
|
63
64
|
- lib/debug/breakpoint.rb
|
64
65
|
- lib/debug/client.rb
|
65
66
|
- lib/debug/color.rb
|