debug 1.5.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +79 -11
- data/README.md +39 -16
- data/Rakefile +25 -7
- data/debug.gemspec +1 -1
- data/exe/rdbg +7 -3
- data/ext/debug/debug.c +0 -22
- data/ext/debug/extconf.rb +18 -7
- data/lib/debug/breakpoint.rb +68 -33
- data/lib/debug/client.rb +12 -2
- data/lib/debug/config.rb +55 -24
- data/lib/debug/console.rb +9 -3
- data/lib/debug/frame_info.rb +31 -24
- data/lib/debug/prelude.rb +1 -0
- data/lib/debug/server.rb +44 -17
- data/lib/debug/server_cdp.rb +5 -5
- data/lib/debug/server_dap.rb +223 -117
- data/lib/debug/session.rb +241 -131
- data/lib/debug/source_repository.rb +13 -0
- data/lib/debug/thread_client.rb +161 -64
- data/lib/debug/tracer.rb +4 -3
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +1 -0
- data/misc/README.md.erb +28 -8
- metadata +5 -6
- data/lib/debug/bp.vim +0 -68
data/lib/debug/session.rb
CHANGED
|
@@ -19,6 +19,15 @@ if $0.end_with?('bin/bundle') && ARGV.first == 'exec'
|
|
|
19
19
|
return
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# restore RUBYOPT
|
|
23
|
+
if (added_opt = ENV['RUBY_DEBUG_ADDED_RUBYOPT']) &&
|
|
24
|
+
(rubyopt = ENV['RUBYOPT']) &&
|
|
25
|
+
rubyopt.end_with?(added_opt)
|
|
26
|
+
|
|
27
|
+
ENV['RUBYOPT'] = rubyopt.delete_suffix(added_opt)
|
|
28
|
+
ENV['RUBY_DEBUG_ADDED_RUBYOPT'] = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
22
31
|
require_relative 'frame_info'
|
|
23
32
|
require_relative 'config'
|
|
24
33
|
require_relative 'thread_client'
|
|
@@ -32,6 +41,7 @@ $LOADED_FEATURES << File.expand_path(File.join(__dir__, '..', 'debug.rb'))
|
|
|
32
41
|
require 'debug' # invalidate the $LOADED_FEATURE cache
|
|
33
42
|
|
|
34
43
|
require 'json' if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal'
|
|
44
|
+
require 'pp'
|
|
35
45
|
|
|
36
46
|
class RubyVM::InstructionSequence
|
|
37
47
|
def traceable_lines_norec lines
|
|
@@ -197,35 +207,44 @@ module DEBUGGER__
|
|
|
197
207
|
deactivate
|
|
198
208
|
end
|
|
199
209
|
|
|
210
|
+
def request_tc(req)
|
|
211
|
+
@tc << req
|
|
212
|
+
end
|
|
213
|
+
|
|
200
214
|
def process_event evt
|
|
201
215
|
# variable `@internal_info` is only used for test
|
|
202
216
|
tc, output, ev, @internal_info, *ev_args = evt
|
|
203
|
-
output.each{|str| @ui.puts str} if ev != :suspend
|
|
204
217
|
|
|
205
|
-
|
|
218
|
+
output.each{|str| @ui.puts str} if ev != :suspend
|
|
206
219
|
|
|
207
|
-
|
|
220
|
+
# special event, tc is nil
|
|
221
|
+
# and we don't want to set @tc to the newly created thread's ThreadClient
|
|
222
|
+
if ev == :thread_begin
|
|
208
223
|
th = ev_args.shift
|
|
209
224
|
q = ev_args.shift
|
|
210
225
|
on_thread_begin th
|
|
211
226
|
q << true
|
|
212
227
|
|
|
228
|
+
return
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
@tc = tc
|
|
232
|
+
|
|
233
|
+
case ev
|
|
213
234
|
when :init
|
|
214
235
|
enter_subsession
|
|
215
|
-
wait_command_loop
|
|
216
|
-
|
|
236
|
+
wait_command_loop
|
|
217
237
|
when :load
|
|
218
238
|
iseq, src = ev_args
|
|
219
239
|
on_load iseq, src
|
|
220
|
-
|
|
221
|
-
tc << :continue
|
|
240
|
+
request_tc :continue
|
|
222
241
|
|
|
223
242
|
when :trace
|
|
224
243
|
trace_id, msg = ev_args
|
|
225
244
|
if t = @tracers.values.find{|t| t.object_id == trace_id}
|
|
226
245
|
t.puts msg
|
|
227
246
|
end
|
|
228
|
-
|
|
247
|
+
request_tc :continue
|
|
229
248
|
|
|
230
249
|
when :suspend
|
|
231
250
|
enter_subsession if ev_args.first != :replay
|
|
@@ -235,24 +254,23 @@ module DEBUGGER__
|
|
|
235
254
|
when :breakpoint
|
|
236
255
|
bp, i = bp_index ev_args[1]
|
|
237
256
|
clean_bps unless bp
|
|
238
|
-
@ui.event :suspend_bp, i, bp, tc.id
|
|
257
|
+
@ui.event :suspend_bp, i, bp, @tc.id
|
|
239
258
|
when :trap
|
|
240
|
-
@ui.event :suspend_trap, sig = ev_args[1], tc.id
|
|
259
|
+
@ui.event :suspend_trap, sig = ev_args[1], @tc.id
|
|
241
260
|
|
|
242
261
|
if sig == :SIGINT && (@intercepted_sigint_cmd.kind_of?(Proc) || @intercepted_sigint_cmd.kind_of?(String))
|
|
243
262
|
@ui.puts "#{@intercepted_sigint_cmd.inspect} is registered as SIGINT handler."
|
|
244
263
|
@ui.puts "`sigint` command execute it."
|
|
245
264
|
end
|
|
246
265
|
else
|
|
247
|
-
@ui.event :suspended, tc.id
|
|
266
|
+
@ui.event :suspended, @tc.id
|
|
248
267
|
end
|
|
249
268
|
|
|
250
269
|
if @displays.empty?
|
|
251
|
-
wait_command_loop
|
|
270
|
+
wait_command_loop
|
|
252
271
|
else
|
|
253
|
-
|
|
272
|
+
request_tc [:eval, :display, @displays]
|
|
254
273
|
end
|
|
255
|
-
|
|
256
274
|
when :result
|
|
257
275
|
raise "[BUG] not in subsession" if @subsession_stack.empty?
|
|
258
276
|
|
|
@@ -283,14 +301,14 @@ module DEBUGGER__
|
|
|
283
301
|
# ignore
|
|
284
302
|
end
|
|
285
303
|
|
|
286
|
-
wait_command_loop
|
|
304
|
+
wait_command_loop
|
|
287
305
|
|
|
288
306
|
when :dap_result
|
|
289
307
|
dap_event ev_args # server.rb
|
|
290
|
-
wait_command_loop
|
|
308
|
+
wait_command_loop
|
|
291
309
|
when :cdp_result
|
|
292
310
|
cdp_event ev_args
|
|
293
|
-
wait_command_loop
|
|
311
|
+
wait_command_loop
|
|
294
312
|
end
|
|
295
313
|
end
|
|
296
314
|
|
|
@@ -323,9 +341,7 @@ module DEBUGGER__
|
|
|
323
341
|
"DEBUGGER__::SESSION"
|
|
324
342
|
end
|
|
325
343
|
|
|
326
|
-
def wait_command_loop
|
|
327
|
-
@tc = tc
|
|
328
|
-
|
|
344
|
+
def wait_command_loop
|
|
329
345
|
loop do
|
|
330
346
|
case wait_command
|
|
331
347
|
when :retry
|
|
@@ -529,32 +545,6 @@ module DEBUGGER__
|
|
|
529
545
|
end
|
|
530
546
|
end
|
|
531
547
|
|
|
532
|
-
# skip
|
|
533
|
-
when 'bv'
|
|
534
|
-
check_postmortem
|
|
535
|
-
require 'json'
|
|
536
|
-
|
|
537
|
-
h = Hash.new{|h, k| h[k] = []}
|
|
538
|
-
@bps.each_value{|bp|
|
|
539
|
-
if LineBreakpoint === bp
|
|
540
|
-
h[bp.path] << {lnum: bp.line}
|
|
541
|
-
end
|
|
542
|
-
}
|
|
543
|
-
if h.empty?
|
|
544
|
-
# TODO: clean?
|
|
545
|
-
else
|
|
546
|
-
open(".rdb_breakpoints.json", 'w'){|f| JSON.dump(h, f)}
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
vimsrc = File.join(__dir__, 'bp.vim')
|
|
550
|
-
system("vim -R -S #{vimsrc} #{@tc.location.path}")
|
|
551
|
-
|
|
552
|
-
if File.exist?(".rdb_breakpoints.json")
|
|
553
|
-
pp JSON.load(File.read(".rdb_breakpoints.json"))
|
|
554
|
-
end
|
|
555
|
-
|
|
556
|
-
return :retry
|
|
557
|
-
|
|
558
548
|
# * `catch <Error>`
|
|
559
549
|
# * Set breakpoint on raising `<Error>`.
|
|
560
550
|
# * `catch ... if: <expr>`
|
|
@@ -632,15 +622,15 @@ module DEBUGGER__
|
|
|
632
622
|
when 'bt', 'backtrace'
|
|
633
623
|
case arg
|
|
634
624
|
when /\A(\d+)\z/
|
|
635
|
-
|
|
625
|
+
request_tc [:show, :backtrace, arg.to_i, nil]
|
|
636
626
|
when /\A\/(.*)\/\z/
|
|
637
627
|
pattern = $1
|
|
638
|
-
|
|
628
|
+
request_tc [:show, :backtrace, nil, Regexp.compile(pattern)]
|
|
639
629
|
when /\A(\d+)\s+\/(.*)\/\z/
|
|
640
630
|
max, pattern = $1, $2
|
|
641
|
-
|
|
631
|
+
request_tc [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
|
|
642
632
|
else
|
|
643
|
-
|
|
633
|
+
request_tc [:show, :backtrace, nil, nil]
|
|
644
634
|
end
|
|
645
635
|
|
|
646
636
|
# * `l[ist]`
|
|
@@ -653,13 +643,13 @@ module DEBUGGER__
|
|
|
653
643
|
when 'l', 'list'
|
|
654
644
|
case arg ? arg.strip : nil
|
|
655
645
|
when /\A(\d+)\z/
|
|
656
|
-
|
|
646
|
+
request_tc [:show, :list, {start_line: arg.to_i - 1}]
|
|
657
647
|
when /\A-\z/
|
|
658
|
-
|
|
648
|
+
request_tc [:show, :list, {dir: -1}]
|
|
659
649
|
when /\A(\d+)-(\d+)\z/
|
|
660
|
-
|
|
650
|
+
request_tc [:show, :list, {start_line: $1.to_i - 1, end_line: $2.to_i}]
|
|
661
651
|
when nil
|
|
662
|
-
|
|
652
|
+
request_tc [:show, :list]
|
|
663
653
|
else
|
|
664
654
|
@ui.puts "Can not handle list argument: #{arg}"
|
|
665
655
|
return :retry
|
|
@@ -683,7 +673,7 @@ module DEBUGGER__
|
|
|
683
673
|
return :retry
|
|
684
674
|
end
|
|
685
675
|
|
|
686
|
-
|
|
676
|
+
request_tc [:show, :edit, arg]
|
|
687
677
|
|
|
688
678
|
# * `i[nfo]`
|
|
689
679
|
# * Show information about current frame (local/instance variables and defined constants).
|
|
@@ -710,15 +700,15 @@ module DEBUGGER__
|
|
|
710
700
|
|
|
711
701
|
case sub
|
|
712
702
|
when nil
|
|
713
|
-
|
|
703
|
+
request_tc [:show, :default, pat] # something useful
|
|
714
704
|
when 'l', /^locals?/
|
|
715
|
-
|
|
705
|
+
request_tc [:show, :locals, pat]
|
|
716
706
|
when 'i', /^ivars?/i, /^instance[_ ]variables?/i
|
|
717
|
-
|
|
707
|
+
request_tc [:show, :ivars, pat]
|
|
718
708
|
when 'c', /^consts?/i, /^constants?/i
|
|
719
|
-
|
|
709
|
+
request_tc [:show, :consts, pat]
|
|
720
710
|
when 'g', /^globals?/i, /^global[_ ]variables?/i
|
|
721
|
-
|
|
711
|
+
request_tc [:show, :globals, pat]
|
|
722
712
|
when 'th', /threads?/
|
|
723
713
|
thread_list
|
|
724
714
|
return :retry
|
|
@@ -734,7 +724,7 @@ module DEBUGGER__
|
|
|
734
724
|
# * Show you available methods and instance variables of the given object.
|
|
735
725
|
# * If the object is a class/module, it also lists its constants.
|
|
736
726
|
when 'outline', 'o', 'ls'
|
|
737
|
-
|
|
727
|
+
request_tc [:show, :outline, arg]
|
|
738
728
|
|
|
739
729
|
# * `display`
|
|
740
730
|
# * Show display setting.
|
|
@@ -743,9 +733,9 @@ module DEBUGGER__
|
|
|
743
733
|
when 'display'
|
|
744
734
|
if arg && !arg.empty?
|
|
745
735
|
@displays << arg
|
|
746
|
-
|
|
736
|
+
request_tc [:eval, :try_display, @displays]
|
|
747
737
|
else
|
|
748
|
-
|
|
738
|
+
request_tc [:eval, :display, @displays]
|
|
749
739
|
end
|
|
750
740
|
|
|
751
741
|
# * `undisplay`
|
|
@@ -758,7 +748,7 @@ module DEBUGGER__
|
|
|
758
748
|
if @displays[n = $1.to_i]
|
|
759
749
|
@displays.delete_at n
|
|
760
750
|
end
|
|
761
|
-
|
|
751
|
+
request_tc [:eval, :display, @displays]
|
|
762
752
|
when nil
|
|
763
753
|
if ask "clear all?", 'N'
|
|
764
754
|
@displays.clear
|
|
@@ -773,29 +763,29 @@ module DEBUGGER__
|
|
|
773
763
|
# * `f[rame] <framenum>`
|
|
774
764
|
# * Specify a current frame. Evaluation are run on specified frame.
|
|
775
765
|
when 'frame', 'f'
|
|
776
|
-
|
|
766
|
+
request_tc [:frame, :set, arg]
|
|
777
767
|
|
|
778
768
|
# * `up`
|
|
779
769
|
# * Specify the upper frame.
|
|
780
770
|
when 'up'
|
|
781
|
-
|
|
771
|
+
request_tc [:frame, :up]
|
|
782
772
|
|
|
783
773
|
# * `down`
|
|
784
774
|
# * Specify the lower frame.
|
|
785
775
|
when 'down'
|
|
786
|
-
|
|
776
|
+
request_tc [:frame, :down]
|
|
787
777
|
|
|
788
778
|
### Evaluate
|
|
789
779
|
|
|
790
780
|
# * `p <expr>`
|
|
791
781
|
# * Evaluate like `p <expr>` on the current frame.
|
|
792
782
|
when 'p'
|
|
793
|
-
|
|
783
|
+
request_tc [:eval, :p, arg.to_s]
|
|
794
784
|
|
|
795
785
|
# * `pp <expr>`
|
|
796
786
|
# * Evaluate like `pp <expr>` on the current frame.
|
|
797
787
|
when 'pp'
|
|
798
|
-
|
|
788
|
+
request_tc [:eval, :pp, arg.to_s]
|
|
799
789
|
|
|
800
790
|
# * `eval <expr>`
|
|
801
791
|
# * Evaluate `<expr>` on the current frame.
|
|
@@ -805,7 +795,7 @@ module DEBUGGER__
|
|
|
805
795
|
@ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
|
|
806
796
|
return :retry
|
|
807
797
|
else
|
|
808
|
-
|
|
798
|
+
request_tc [:eval, :call, arg]
|
|
809
799
|
end
|
|
810
800
|
|
|
811
801
|
# * `irb`
|
|
@@ -815,7 +805,7 @@ module DEBUGGER__
|
|
|
815
805
|
@ui.puts "not supported on the remote console."
|
|
816
806
|
return :retry
|
|
817
807
|
end
|
|
818
|
-
|
|
808
|
+
request_tc [:eval, :irb]
|
|
819
809
|
|
|
820
810
|
# don't repeat irb command
|
|
821
811
|
@repl_prev_line = nil
|
|
@@ -872,7 +862,7 @@ module DEBUGGER__
|
|
|
872
862
|
return :retry
|
|
873
863
|
|
|
874
864
|
when /\Aobject\s+(.+)/
|
|
875
|
-
|
|
865
|
+
request_tc [:trace, :object, $1.strip, {pattern: pattern, into: into}]
|
|
876
866
|
|
|
877
867
|
when /\Aoff\s+(\d+)\z/
|
|
878
868
|
if t = @tracers.values[$1.to_i]
|
|
@@ -910,7 +900,7 @@ module DEBUGGER__
|
|
|
910
900
|
when 'record'
|
|
911
901
|
case arg
|
|
912
902
|
when nil, 'on', 'off'
|
|
913
|
-
|
|
903
|
+
request_tc [:record, arg&.to_sym]
|
|
914
904
|
else
|
|
915
905
|
@ui.puts "unknown command: #{arg}"
|
|
916
906
|
return :retry
|
|
@@ -1005,7 +995,7 @@ module DEBUGGER__
|
|
|
1005
995
|
|
|
1006
996
|
### END
|
|
1007
997
|
else
|
|
1008
|
-
|
|
998
|
+
request_tc [:eval, :pp, line]
|
|
1009
999
|
=begin
|
|
1010
1000
|
@repl_prev_line = nil
|
|
1011
1001
|
@ui.puts "unknown command: #{line}"
|
|
@@ -1062,7 +1052,7 @@ module DEBUGGER__
|
|
|
1062
1052
|
case arg
|
|
1063
1053
|
when nil, /\A\d+\z/
|
|
1064
1054
|
if type == :in && @tc.recorder&.replaying?
|
|
1065
|
-
|
|
1055
|
+
request_tc [:step, type, arg&.to_i]
|
|
1066
1056
|
else
|
|
1067
1057
|
leave_subsession [:step, type, arg&.to_i]
|
|
1068
1058
|
end
|
|
@@ -1071,7 +1061,7 @@ module DEBUGGER__
|
|
|
1071
1061
|
@ui.puts "only `step #{arg}` is supported."
|
|
1072
1062
|
:retry
|
|
1073
1063
|
else
|
|
1074
|
-
|
|
1064
|
+
request_tc [:step, arg.to_sym]
|
|
1075
1065
|
end
|
|
1076
1066
|
else
|
|
1077
1067
|
@ui.puts "Unknown option: #{arg}"
|
|
@@ -1081,11 +1071,18 @@ module DEBUGGER__
|
|
|
1081
1071
|
|
|
1082
1072
|
def config_show key
|
|
1083
1073
|
key = key.to_sym
|
|
1084
|
-
|
|
1074
|
+
config_detail = CONFIG_SET[key]
|
|
1075
|
+
|
|
1076
|
+
if config_detail
|
|
1085
1077
|
v = CONFIG[key]
|
|
1086
|
-
kv = "#{key} = #{v.
|
|
1087
|
-
desc =
|
|
1088
|
-
|
|
1078
|
+
kv = "#{key} = #{v.inspect}"
|
|
1079
|
+
desc = config_detail[1]
|
|
1080
|
+
|
|
1081
|
+
if config_default = config_detail[3]
|
|
1082
|
+
desc += " (default: #{config_default})"
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
line = "%-34s \# %s" % [kv, desc]
|
|
1089
1086
|
if line.size > SESSION.width
|
|
1090
1087
|
@ui.puts "\# #{desc}\n#{kv}"
|
|
1091
1088
|
else
|
|
@@ -1135,7 +1132,7 @@ module DEBUGGER__
|
|
|
1135
1132
|
config_set $1, $2, append: true
|
|
1136
1133
|
|
|
1137
1134
|
when /\A\s*append\s+(\w+)\s+(.+)\z/
|
|
1138
|
-
config_set $1, $2
|
|
1135
|
+
config_set $1, $2, append: true
|
|
1139
1136
|
|
|
1140
1137
|
when /\A(\w+)\z/
|
|
1141
1138
|
config_show $1
|
|
@@ -1261,9 +1258,12 @@ module DEBUGGER__
|
|
|
1261
1258
|
@repl_prev_line = nil
|
|
1262
1259
|
|
|
1263
1260
|
if @bps.has_key? bp.key
|
|
1264
|
-
|
|
1261
|
+
if bp.duplicable?
|
|
1262
|
+
bp
|
|
1263
|
+
else
|
|
1265
1264
|
@ui.puts "duplicated breakpoint: #{bp}"
|
|
1266
1265
|
bp.disable
|
|
1266
|
+
nil
|
|
1267
1267
|
end
|
|
1268
1268
|
else
|
|
1269
1269
|
@bps[bp.key] = bp
|
|
@@ -1320,7 +1320,7 @@ module DEBUGGER__
|
|
|
1320
1320
|
when /\A(.+)[:\s+](\d+)\z/
|
|
1321
1321
|
add_line_breakpoint $1, $2.to_i, cond: cond, command: cmd
|
|
1322
1322
|
when /\A(.+)([\.\#])(.+)\z/
|
|
1323
|
-
|
|
1323
|
+
request_tc [:breakpoint, :method, $1, $2, $3, cond, cmd, path]
|
|
1324
1324
|
return :noretry
|
|
1325
1325
|
when nil
|
|
1326
1326
|
add_check_breakpoint cond, path, cmd
|
|
@@ -1347,11 +1347,11 @@ module DEBUGGER__
|
|
|
1347
1347
|
cmd = ['watch', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
|
1348
1348
|
path = Regexp.compile(expr[:path]) if expr[:path]
|
|
1349
1349
|
|
|
1350
|
-
|
|
1350
|
+
request_tc [:breakpoint, :watch, expr[:sig], cond, cmd, path]
|
|
1351
1351
|
end
|
|
1352
1352
|
|
|
1353
|
-
def add_catch_breakpoint pat
|
|
1354
|
-
bp = CatchBreakpoint.new(pat)
|
|
1353
|
+
def add_catch_breakpoint pat, cond: nil
|
|
1354
|
+
bp = CatchBreakpoint.new(pat, cond: cond)
|
|
1355
1355
|
add_bp bp
|
|
1356
1356
|
end
|
|
1357
1357
|
|
|
@@ -1369,15 +1369,34 @@ module DEBUGGER__
|
|
|
1369
1369
|
@ui.puts e.message
|
|
1370
1370
|
end
|
|
1371
1371
|
|
|
1372
|
-
def
|
|
1373
|
-
path = resolve_path(path)
|
|
1372
|
+
def clear_breakpoints(&condition)
|
|
1374
1373
|
@bps.delete_if do |k, bp|
|
|
1375
|
-
if
|
|
1374
|
+
if condition.call(k, bp)
|
|
1376
1375
|
bp.delete
|
|
1376
|
+
true
|
|
1377
1377
|
end
|
|
1378
1378
|
end
|
|
1379
1379
|
end
|
|
1380
1380
|
|
|
1381
|
+
def clear_line_breakpoints path
|
|
1382
|
+
path = resolve_path(path)
|
|
1383
|
+
clear_breakpoints do |k, bp|
|
|
1384
|
+
bp.is_a?(LineBreakpoint) && DEBUGGER__.compare_path(k.first, path)
|
|
1385
|
+
end
|
|
1386
|
+
rescue Errno::ENOENT
|
|
1387
|
+
# just ignore
|
|
1388
|
+
end
|
|
1389
|
+
|
|
1390
|
+
def clear_catch_breakpoints *exception_names
|
|
1391
|
+
clear_breakpoints do |k, bp|
|
|
1392
|
+
bp.is_a?(CatchBreakpoint) && exception_names.include?(k[1])
|
|
1393
|
+
end
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
def clear_all_breakpoints
|
|
1397
|
+
clear_breakpoints{true}
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1381
1400
|
def add_iseq_breakpoint iseq, **kw
|
|
1382
1401
|
bp = ISeqBreakpoint.new(iseq, [:line], **kw)
|
|
1383
1402
|
add_bp bp
|
|
@@ -1568,7 +1587,7 @@ module DEBUGGER__
|
|
|
1568
1587
|
DEBUGGER__.info "Leave subsession (nested #{@subsession_stack.size})"
|
|
1569
1588
|
end
|
|
1570
1589
|
|
|
1571
|
-
|
|
1590
|
+
request_tc type if type
|
|
1572
1591
|
@tc = nil
|
|
1573
1592
|
rescue Exception => e
|
|
1574
1593
|
STDERR.puts PP.pp([e, e.backtrace], ''.dup)
|
|
@@ -1583,7 +1602,9 @@ module DEBUGGER__
|
|
|
1583
1602
|
|
|
1584
1603
|
def on_load iseq, src
|
|
1585
1604
|
DEBUGGER__.info "Load #{iseq.absolute_path || iseq.path}"
|
|
1586
|
-
|
|
1605
|
+
|
|
1606
|
+
file_path, reloaded = @sr.add(iseq, src)
|
|
1607
|
+
@ui.event :load, file_path, reloaded
|
|
1587
1608
|
|
|
1588
1609
|
pending_line_breakpoints = @bps.find_all do |key, bp|
|
|
1589
1610
|
LineBreakpoint === bp && !bp.iseq
|
|
@@ -1591,7 +1612,18 @@ module DEBUGGER__
|
|
|
1591
1612
|
|
|
1592
1613
|
pending_line_breakpoints.each do |_key, bp|
|
|
1593
1614
|
if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
|
|
1594
|
-
bp.try_activate
|
|
1615
|
+
bp.try_activate iseq
|
|
1616
|
+
end
|
|
1617
|
+
end
|
|
1618
|
+
|
|
1619
|
+
if reloaded
|
|
1620
|
+
@bps.find_all do |key, bp|
|
|
1621
|
+
LineBreakpoint === bp && DEBUGGER__.compare_path(bp.path, file_path)
|
|
1622
|
+
end.each do |_key, bp|
|
|
1623
|
+
@bps.delete bp.key # to allow duplicate
|
|
1624
|
+
if nbp = LineBreakpoint.copy(bp, iseq)
|
|
1625
|
+
add_bp nbp
|
|
1626
|
+
end
|
|
1595
1627
|
end
|
|
1596
1628
|
end
|
|
1597
1629
|
end
|
|
@@ -1616,9 +1648,10 @@ module DEBUGGER__
|
|
|
1616
1648
|
|
|
1617
1649
|
def method_added tp
|
|
1618
1650
|
b = tp.binding
|
|
1651
|
+
|
|
1619
1652
|
if var_name = b.local_variables.first
|
|
1620
1653
|
mid = b.local_variable_get(var_name)
|
|
1621
|
-
|
|
1654
|
+
resolved = true
|
|
1622
1655
|
|
|
1623
1656
|
@bps.each{|k, bp|
|
|
1624
1657
|
case bp
|
|
@@ -1629,15 +1662,57 @@ module DEBUGGER__
|
|
|
1629
1662
|
end
|
|
1630
1663
|
end
|
|
1631
1664
|
|
|
1632
|
-
|
|
1665
|
+
resolved = false if !bp.enabled?
|
|
1633
1666
|
end
|
|
1634
1667
|
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1668
|
+
|
|
1669
|
+
if resolved
|
|
1670
|
+
Session.deactivate_method_added_trackers
|
|
1671
|
+
end
|
|
1672
|
+
|
|
1673
|
+
case mid
|
|
1674
|
+
when :method_added, :singleton_method_added
|
|
1675
|
+
Session.create_method_added_tracker(tp.self, mid)
|
|
1676
|
+
Session.activate_method_added_trackers unless resolved
|
|
1637
1677
|
end
|
|
1638
1678
|
end
|
|
1639
1679
|
end
|
|
1640
1680
|
|
|
1681
|
+
class ::Module
|
|
1682
|
+
undef method_added
|
|
1683
|
+
def method_added mid; end
|
|
1684
|
+
end
|
|
1685
|
+
|
|
1686
|
+
class ::BasicObject
|
|
1687
|
+
undef singleton_method_added
|
|
1688
|
+
def singleton_method_added mid; end
|
|
1689
|
+
end
|
|
1690
|
+
|
|
1691
|
+
def self.create_method_added_tracker mod, method_added_id, method_accessor = :method
|
|
1692
|
+
m = mod.__send__(method_accessor, method_added_id)
|
|
1693
|
+
METHOD_ADDED_TRACKERS[m] = TracePoint.new(:call) do |tp|
|
|
1694
|
+
SESSION.method_added tp
|
|
1695
|
+
end
|
|
1696
|
+
end
|
|
1697
|
+
|
|
1698
|
+
def self.activate_method_added_trackers
|
|
1699
|
+
METHOD_ADDED_TRACKERS.each do |m, tp|
|
|
1700
|
+
tp.enable(target: m) unless tp.enabled?
|
|
1701
|
+
rescue ArgumentError
|
|
1702
|
+
DEBUGGER__.warn "Methods defined under #{m.owner} can not track by the debugger."
|
|
1703
|
+
end
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
def self.deactivate_method_added_trackers
|
|
1707
|
+
METHOD_ADDED_TRACKERS.each do |m, tp|
|
|
1708
|
+
tp.disable if tp.enabled?
|
|
1709
|
+
end
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1712
|
+
METHOD_ADDED_TRACKERS = Hash.new
|
|
1713
|
+
create_method_added_tracker Module, :method_added, :instance_method
|
|
1714
|
+
create_method_added_tracker BasicObject, :singleton_method_added, :instance_method
|
|
1715
|
+
|
|
1641
1716
|
def width
|
|
1642
1717
|
@ui.width
|
|
1643
1718
|
end
|
|
@@ -2051,34 +2126,53 @@ module DEBUGGER__
|
|
|
2051
2126
|
end
|
|
2052
2127
|
end
|
|
2053
2128
|
|
|
2054
|
-
|
|
2055
|
-
undef method_added
|
|
2056
|
-
def method_added mid; end
|
|
2057
|
-
def singleton_method_added mid; end
|
|
2058
|
-
end
|
|
2129
|
+
# Inspector
|
|
2059
2130
|
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2131
|
+
SHORT_INSPECT_LENGTH = 40
|
|
2132
|
+
|
|
2133
|
+
class LimitedPP
|
|
2134
|
+
def self.pp(obj, max=80)
|
|
2135
|
+
out = self.new(max)
|
|
2136
|
+
catch out do
|
|
2137
|
+
PP.singleline_pp(obj, out)
|
|
2138
|
+
end
|
|
2139
|
+
out.buf
|
|
2065
2140
|
end
|
|
2066
|
-
end
|
|
2067
2141
|
|
|
2068
|
-
|
|
2142
|
+
attr_reader :buf
|
|
2069
2143
|
|
|
2070
|
-
|
|
2144
|
+
def initialize max
|
|
2145
|
+
@max = max
|
|
2146
|
+
@cnt = 0
|
|
2147
|
+
@buf = String.new
|
|
2148
|
+
end
|
|
2071
2149
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2150
|
+
def <<(other)
|
|
2151
|
+
@buf << other
|
|
2152
|
+
|
|
2153
|
+
if @buf.size >= @max
|
|
2154
|
+
@buf = @buf[0..@max] + '...'
|
|
2155
|
+
throw self
|
|
2156
|
+
end
|
|
2157
|
+
end
|
|
2158
|
+
end
|
|
2074
2159
|
|
|
2075
|
-
|
|
2076
|
-
|
|
2160
|
+
def self.safe_inspect obj, max_length: SHORT_INSPECT_LENGTH, short: false
|
|
2161
|
+
if short
|
|
2162
|
+
LimitedPP.pp(obj, max_length)
|
|
2163
|
+
else
|
|
2164
|
+
obj.inspect
|
|
2165
|
+
end
|
|
2166
|
+
rescue NoMethodError => e
|
|
2167
|
+
klass, oid = M_CLASS.bind_call(obj), M_OBJECT_ID.bind_call(obj)
|
|
2168
|
+
if obj == (r = e.receiver)
|
|
2169
|
+
"<\##{klass.name}#{oid} does not have \#inspect>"
|
|
2077
2170
|
else
|
|
2078
|
-
|
|
2171
|
+
rklass, roid = M_CLASS.bind_call(r), M_OBJECT_ID.bind_call(r)
|
|
2172
|
+
"<\##{klass.name}:#{roid} contains <\##{rklass}:#{roid} and it does not have #inspect>"
|
|
2079
2173
|
end
|
|
2080
2174
|
rescue Exception => e
|
|
2081
|
-
|
|
2175
|
+
"<#inspect raises #{e.inspect}>"
|
|
2082
2176
|
end
|
|
2083
2177
|
|
|
2084
2178
|
def self.warn msg
|
|
@@ -2089,18 +2183,27 @@ module DEBUGGER__
|
|
|
2089
2183
|
log :INFO, msg
|
|
2090
2184
|
end
|
|
2091
2185
|
|
|
2092
|
-
def self.
|
|
2093
|
-
@logfile = STDERR unless defined? @logfile
|
|
2094
|
-
|
|
2186
|
+
def self.check_loglevel level
|
|
2095
2187
|
lv = LOG_LEVELS[level]
|
|
2096
|
-
config_lv = LOG_LEVELS[CONFIG[:log_level]
|
|
2188
|
+
config_lv = LOG_LEVELS[CONFIG[:log_level]]
|
|
2189
|
+
lv <= config_lv
|
|
2190
|
+
end
|
|
2097
2191
|
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2192
|
+
def self.debug(&b)
|
|
2193
|
+
if check_loglevel :DEBUG
|
|
2194
|
+
log :DEBUG, b.call
|
|
2101
2195
|
end
|
|
2196
|
+
end
|
|
2197
|
+
|
|
2198
|
+
def self.log level, msg
|
|
2199
|
+
if check_loglevel level
|
|
2200
|
+
@logfile = STDERR unless defined? @logfile
|
|
2201
|
+
|
|
2202
|
+
if defined? SESSION
|
|
2203
|
+
pi = SESSION.process_info
|
|
2204
|
+
process_info = pi ? "[#{pi}]" : nil
|
|
2205
|
+
end
|
|
2102
2206
|
|
|
2103
|
-
if lv <= config_lv
|
|
2104
2207
|
if level == :WARN
|
|
2105
2208
|
# :WARN on debugger is general information
|
|
2106
2209
|
@logfile.puts "DEBUGGER#{process_info}: #{msg}"
|
|
@@ -2137,7 +2240,7 @@ module DEBUGGER__
|
|
|
2137
2240
|
module ForkInterceptor
|
|
2138
2241
|
if Process.respond_to? :_fork
|
|
2139
2242
|
def _fork
|
|
2140
|
-
return
|
|
2243
|
+
return super unless defined?(SESSION) && SESSION.active?
|
|
2141
2244
|
|
|
2142
2245
|
parent_hook, child_hook = __fork_setup_for_debugger
|
|
2143
2246
|
|
|
@@ -2153,7 +2256,7 @@ module DEBUGGER__
|
|
|
2153
2256
|
end
|
|
2154
2257
|
else
|
|
2155
2258
|
def fork(&given_block)
|
|
2156
|
-
return
|
|
2259
|
+
return super unless defined?(SESSION) && SESSION.active?
|
|
2157
2260
|
parent_hook, child_hook = __fork_setup_for_debugger
|
|
2158
2261
|
|
|
2159
2262
|
if given_block
|
|
@@ -2178,12 +2281,10 @@ module DEBUGGER__
|
|
|
2178
2281
|
end
|
|
2179
2282
|
|
|
2180
2283
|
private def __fork_setup_for_debugger
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
fork_mode = :both
|
|
2186
|
-
end
|
|
2284
|
+
fork_mode = CONFIG[:fork_mode]
|
|
2285
|
+
|
|
2286
|
+
if fork_mode == :both && CONFIG[:parent_on_fork]
|
|
2287
|
+
fork_mode = :parent
|
|
2187
2288
|
end
|
|
2188
2289
|
|
|
2189
2290
|
parent_pid = Process.pid
|
|
@@ -2310,3 +2411,12 @@ class Binding
|
|
|
2310
2411
|
alias break debugger
|
|
2311
2412
|
alias b debugger
|
|
2312
2413
|
end
|
|
2414
|
+
|
|
2415
|
+
# for Ruby 2.6 compatibility
|
|
2416
|
+
unless method(:p).unbind.respond_to? :bind_call
|
|
2417
|
+
class UnboundMethod
|
|
2418
|
+
def bind_call(obj, *args)
|
|
2419
|
+
self.bind(obj).call(*args)
|
|
2420
|
+
end
|
|
2421
|
+
end
|
|
2422
|
+
end
|