debug 1.5.0 → 1.6.0
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/server.rb +44 -17
- data/lib/debug/server_cdp.rb +5 -5
- data/lib/debug/server_dap.rb +221 -115
- data/lib/debug/session.rb +227 -129
- 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/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,14 @@ 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.start_with?(added_opt)
|
26
|
+
ENV['RUBYOPT'] = rubyopt.delete_prefix(rubyopt)
|
27
|
+
ENV['RUBY_DEBUG_ADDED_RUBYOPT'] = nil
|
28
|
+
end
|
29
|
+
|
22
30
|
require_relative 'frame_info'
|
23
31
|
require_relative 'config'
|
24
32
|
require_relative 'thread_client'
|
@@ -32,6 +40,7 @@ $LOADED_FEATURES << File.expand_path(File.join(__dir__, '..', 'debug.rb'))
|
|
32
40
|
require 'debug' # invalidate the $LOADED_FEATURE cache
|
33
41
|
|
34
42
|
require 'json' if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal'
|
43
|
+
require 'pp'
|
35
44
|
|
36
45
|
class RubyVM::InstructionSequence
|
37
46
|
def traceable_lines_norec lines
|
@@ -197,9 +206,14 @@ module DEBUGGER__
|
|
197
206
|
deactivate
|
198
207
|
end
|
199
208
|
|
209
|
+
def request_tc(req)
|
210
|
+
@tc << req
|
211
|
+
end
|
212
|
+
|
200
213
|
def process_event evt
|
201
214
|
# variable `@internal_info` is only used for test
|
202
|
-
tc, output, ev, @internal_info, *ev_args = evt
|
215
|
+
@tc, output, ev, @internal_info, *ev_args = evt
|
216
|
+
|
203
217
|
output.each{|str| @ui.puts str} if ev != :suspend
|
204
218
|
|
205
219
|
case ev
|
@@ -212,20 +226,18 @@ module DEBUGGER__
|
|
212
226
|
|
213
227
|
when :init
|
214
228
|
enter_subsession
|
215
|
-
wait_command_loop
|
216
|
-
|
229
|
+
wait_command_loop
|
217
230
|
when :load
|
218
231
|
iseq, src = ev_args
|
219
232
|
on_load iseq, src
|
220
|
-
|
221
|
-
tc << :continue
|
233
|
+
request_tc :continue
|
222
234
|
|
223
235
|
when :trace
|
224
236
|
trace_id, msg = ev_args
|
225
237
|
if t = @tracers.values.find{|t| t.object_id == trace_id}
|
226
238
|
t.puts msg
|
227
239
|
end
|
228
|
-
|
240
|
+
request_tc :continue
|
229
241
|
|
230
242
|
when :suspend
|
231
243
|
enter_subsession if ev_args.first != :replay
|
@@ -235,24 +247,23 @@ module DEBUGGER__
|
|
235
247
|
when :breakpoint
|
236
248
|
bp, i = bp_index ev_args[1]
|
237
249
|
clean_bps unless bp
|
238
|
-
@ui.event :suspend_bp, i, bp, tc.id
|
250
|
+
@ui.event :suspend_bp, i, bp, @tc.id
|
239
251
|
when :trap
|
240
|
-
@ui.event :suspend_trap, sig = ev_args[1], tc.id
|
252
|
+
@ui.event :suspend_trap, sig = ev_args[1], @tc.id
|
241
253
|
|
242
254
|
if sig == :SIGINT && (@intercepted_sigint_cmd.kind_of?(Proc) || @intercepted_sigint_cmd.kind_of?(String))
|
243
255
|
@ui.puts "#{@intercepted_sigint_cmd.inspect} is registered as SIGINT handler."
|
244
256
|
@ui.puts "`sigint` command execute it."
|
245
257
|
end
|
246
258
|
else
|
247
|
-
@ui.event :suspended, tc.id
|
259
|
+
@ui.event :suspended, @tc.id
|
248
260
|
end
|
249
261
|
|
250
262
|
if @displays.empty?
|
251
|
-
wait_command_loop
|
263
|
+
wait_command_loop
|
252
264
|
else
|
253
|
-
|
265
|
+
request_tc [:eval, :display, @displays]
|
254
266
|
end
|
255
|
-
|
256
267
|
when :result
|
257
268
|
raise "[BUG] not in subsession" if @subsession_stack.empty?
|
258
269
|
|
@@ -283,14 +294,14 @@ module DEBUGGER__
|
|
283
294
|
# ignore
|
284
295
|
end
|
285
296
|
|
286
|
-
wait_command_loop
|
297
|
+
wait_command_loop
|
287
298
|
|
288
299
|
when :dap_result
|
289
300
|
dap_event ev_args # server.rb
|
290
|
-
wait_command_loop
|
301
|
+
wait_command_loop
|
291
302
|
when :cdp_result
|
292
303
|
cdp_event ev_args
|
293
|
-
wait_command_loop
|
304
|
+
wait_command_loop
|
294
305
|
end
|
295
306
|
end
|
296
307
|
|
@@ -323,9 +334,7 @@ module DEBUGGER__
|
|
323
334
|
"DEBUGGER__::SESSION"
|
324
335
|
end
|
325
336
|
|
326
|
-
def wait_command_loop
|
327
|
-
@tc = tc
|
328
|
-
|
337
|
+
def wait_command_loop
|
329
338
|
loop do
|
330
339
|
case wait_command
|
331
340
|
when :retry
|
@@ -529,32 +538,6 @@ module DEBUGGER__
|
|
529
538
|
end
|
530
539
|
end
|
531
540
|
|
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
541
|
# * `catch <Error>`
|
559
542
|
# * Set breakpoint on raising `<Error>`.
|
560
543
|
# * `catch ... if: <expr>`
|
@@ -632,15 +615,15 @@ module DEBUGGER__
|
|
632
615
|
when 'bt', 'backtrace'
|
633
616
|
case arg
|
634
617
|
when /\A(\d+)\z/
|
635
|
-
|
618
|
+
request_tc [:show, :backtrace, arg.to_i, nil]
|
636
619
|
when /\A\/(.*)\/\z/
|
637
620
|
pattern = $1
|
638
|
-
|
621
|
+
request_tc [:show, :backtrace, nil, Regexp.compile(pattern)]
|
639
622
|
when /\A(\d+)\s+\/(.*)\/\z/
|
640
623
|
max, pattern = $1, $2
|
641
|
-
|
624
|
+
request_tc [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
|
642
625
|
else
|
643
|
-
|
626
|
+
request_tc [:show, :backtrace, nil, nil]
|
644
627
|
end
|
645
628
|
|
646
629
|
# * `l[ist]`
|
@@ -653,13 +636,13 @@ module DEBUGGER__
|
|
653
636
|
when 'l', 'list'
|
654
637
|
case arg ? arg.strip : nil
|
655
638
|
when /\A(\d+)\z/
|
656
|
-
|
639
|
+
request_tc [:show, :list, {start_line: arg.to_i - 1}]
|
657
640
|
when /\A-\z/
|
658
|
-
|
641
|
+
request_tc [:show, :list, {dir: -1}]
|
659
642
|
when /\A(\d+)-(\d+)\z/
|
660
|
-
|
643
|
+
request_tc [:show, :list, {start_line: $1.to_i - 1, end_line: $2.to_i}]
|
661
644
|
when nil
|
662
|
-
|
645
|
+
request_tc [:show, :list]
|
663
646
|
else
|
664
647
|
@ui.puts "Can not handle list argument: #{arg}"
|
665
648
|
return :retry
|
@@ -683,7 +666,7 @@ module DEBUGGER__
|
|
683
666
|
return :retry
|
684
667
|
end
|
685
668
|
|
686
|
-
|
669
|
+
request_tc [:show, :edit, arg]
|
687
670
|
|
688
671
|
# * `i[nfo]`
|
689
672
|
# * Show information about current frame (local/instance variables and defined constants).
|
@@ -710,15 +693,15 @@ module DEBUGGER__
|
|
710
693
|
|
711
694
|
case sub
|
712
695
|
when nil
|
713
|
-
|
696
|
+
request_tc [:show, :default, pat] # something useful
|
714
697
|
when 'l', /^locals?/
|
715
|
-
|
698
|
+
request_tc [:show, :locals, pat]
|
716
699
|
when 'i', /^ivars?/i, /^instance[_ ]variables?/i
|
717
|
-
|
700
|
+
request_tc [:show, :ivars, pat]
|
718
701
|
when 'c', /^consts?/i, /^constants?/i
|
719
|
-
|
702
|
+
request_tc [:show, :consts, pat]
|
720
703
|
when 'g', /^globals?/i, /^global[_ ]variables?/i
|
721
|
-
|
704
|
+
request_tc [:show, :globals, pat]
|
722
705
|
when 'th', /threads?/
|
723
706
|
thread_list
|
724
707
|
return :retry
|
@@ -734,7 +717,7 @@ module DEBUGGER__
|
|
734
717
|
# * Show you available methods and instance variables of the given object.
|
735
718
|
# * If the object is a class/module, it also lists its constants.
|
736
719
|
when 'outline', 'o', 'ls'
|
737
|
-
|
720
|
+
request_tc [:show, :outline, arg]
|
738
721
|
|
739
722
|
# * `display`
|
740
723
|
# * Show display setting.
|
@@ -743,9 +726,9 @@ module DEBUGGER__
|
|
743
726
|
when 'display'
|
744
727
|
if arg && !arg.empty?
|
745
728
|
@displays << arg
|
746
|
-
|
729
|
+
request_tc [:eval, :try_display, @displays]
|
747
730
|
else
|
748
|
-
|
731
|
+
request_tc [:eval, :display, @displays]
|
749
732
|
end
|
750
733
|
|
751
734
|
# * `undisplay`
|
@@ -758,7 +741,7 @@ module DEBUGGER__
|
|
758
741
|
if @displays[n = $1.to_i]
|
759
742
|
@displays.delete_at n
|
760
743
|
end
|
761
|
-
|
744
|
+
request_tc [:eval, :display, @displays]
|
762
745
|
when nil
|
763
746
|
if ask "clear all?", 'N'
|
764
747
|
@displays.clear
|
@@ -773,29 +756,29 @@ module DEBUGGER__
|
|
773
756
|
# * `f[rame] <framenum>`
|
774
757
|
# * Specify a current frame. Evaluation are run on specified frame.
|
775
758
|
when 'frame', 'f'
|
776
|
-
|
759
|
+
request_tc [:frame, :set, arg]
|
777
760
|
|
778
761
|
# * `up`
|
779
762
|
# * Specify the upper frame.
|
780
763
|
when 'up'
|
781
|
-
|
764
|
+
request_tc [:frame, :up]
|
782
765
|
|
783
766
|
# * `down`
|
784
767
|
# * Specify the lower frame.
|
785
768
|
when 'down'
|
786
|
-
|
769
|
+
request_tc [:frame, :down]
|
787
770
|
|
788
771
|
### Evaluate
|
789
772
|
|
790
773
|
# * `p <expr>`
|
791
774
|
# * Evaluate like `p <expr>` on the current frame.
|
792
775
|
when 'p'
|
793
|
-
|
776
|
+
request_tc [:eval, :p, arg.to_s]
|
794
777
|
|
795
778
|
# * `pp <expr>`
|
796
779
|
# * Evaluate like `pp <expr>` on the current frame.
|
797
780
|
when 'pp'
|
798
|
-
|
781
|
+
request_tc [:eval, :pp, arg.to_s]
|
799
782
|
|
800
783
|
# * `eval <expr>`
|
801
784
|
# * Evaluate `<expr>` on the current frame.
|
@@ -805,7 +788,7 @@ module DEBUGGER__
|
|
805
788
|
@ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
|
806
789
|
return :retry
|
807
790
|
else
|
808
|
-
|
791
|
+
request_tc [:eval, :call, arg]
|
809
792
|
end
|
810
793
|
|
811
794
|
# * `irb`
|
@@ -815,7 +798,7 @@ module DEBUGGER__
|
|
815
798
|
@ui.puts "not supported on the remote console."
|
816
799
|
return :retry
|
817
800
|
end
|
818
|
-
|
801
|
+
request_tc [:eval, :irb]
|
819
802
|
|
820
803
|
# don't repeat irb command
|
821
804
|
@repl_prev_line = nil
|
@@ -872,7 +855,7 @@ module DEBUGGER__
|
|
872
855
|
return :retry
|
873
856
|
|
874
857
|
when /\Aobject\s+(.+)/
|
875
|
-
|
858
|
+
request_tc [:trace, :object, $1.strip, {pattern: pattern, into: into}]
|
876
859
|
|
877
860
|
when /\Aoff\s+(\d+)\z/
|
878
861
|
if t = @tracers.values[$1.to_i]
|
@@ -910,7 +893,7 @@ module DEBUGGER__
|
|
910
893
|
when 'record'
|
911
894
|
case arg
|
912
895
|
when nil, 'on', 'off'
|
913
|
-
|
896
|
+
request_tc [:record, arg&.to_sym]
|
914
897
|
else
|
915
898
|
@ui.puts "unknown command: #{arg}"
|
916
899
|
return :retry
|
@@ -1005,7 +988,7 @@ module DEBUGGER__
|
|
1005
988
|
|
1006
989
|
### END
|
1007
990
|
else
|
1008
|
-
|
991
|
+
request_tc [:eval, :pp, line]
|
1009
992
|
=begin
|
1010
993
|
@repl_prev_line = nil
|
1011
994
|
@ui.puts "unknown command: #{line}"
|
@@ -1062,7 +1045,7 @@ module DEBUGGER__
|
|
1062
1045
|
case arg
|
1063
1046
|
when nil, /\A\d+\z/
|
1064
1047
|
if type == :in && @tc.recorder&.replaying?
|
1065
|
-
|
1048
|
+
request_tc [:step, type, arg&.to_i]
|
1066
1049
|
else
|
1067
1050
|
leave_subsession [:step, type, arg&.to_i]
|
1068
1051
|
end
|
@@ -1071,7 +1054,7 @@ module DEBUGGER__
|
|
1071
1054
|
@ui.puts "only `step #{arg}` is supported."
|
1072
1055
|
:retry
|
1073
1056
|
else
|
1074
|
-
|
1057
|
+
request_tc [:step, arg.to_sym]
|
1075
1058
|
end
|
1076
1059
|
else
|
1077
1060
|
@ui.puts "Unknown option: #{arg}"
|
@@ -1081,11 +1064,18 @@ module DEBUGGER__
|
|
1081
1064
|
|
1082
1065
|
def config_show key
|
1083
1066
|
key = key.to_sym
|
1084
|
-
|
1067
|
+
config_detail = CONFIG_SET[key]
|
1068
|
+
|
1069
|
+
if config_detail
|
1085
1070
|
v = CONFIG[key]
|
1086
|
-
kv = "#{key} = #{v.
|
1087
|
-
desc =
|
1088
|
-
|
1071
|
+
kv = "#{key} = #{v.inspect}"
|
1072
|
+
desc = config_detail[1]
|
1073
|
+
|
1074
|
+
if config_default = config_detail[3]
|
1075
|
+
desc += " (default: #{config_default})"
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
line = "%-34s \# %s" % [kv, desc]
|
1089
1079
|
if line.size > SESSION.width
|
1090
1080
|
@ui.puts "\# #{desc}\n#{kv}"
|
1091
1081
|
else
|
@@ -1135,7 +1125,7 @@ module DEBUGGER__
|
|
1135
1125
|
config_set $1, $2, append: true
|
1136
1126
|
|
1137
1127
|
when /\A\s*append\s+(\w+)\s+(.+)\z/
|
1138
|
-
config_set $1, $2
|
1128
|
+
config_set $1, $2, append: true
|
1139
1129
|
|
1140
1130
|
when /\A(\w+)\z/
|
1141
1131
|
config_show $1
|
@@ -1261,9 +1251,12 @@ module DEBUGGER__
|
|
1261
1251
|
@repl_prev_line = nil
|
1262
1252
|
|
1263
1253
|
if @bps.has_key? bp.key
|
1264
|
-
|
1254
|
+
if bp.duplicable?
|
1255
|
+
bp
|
1256
|
+
else
|
1265
1257
|
@ui.puts "duplicated breakpoint: #{bp}"
|
1266
1258
|
bp.disable
|
1259
|
+
nil
|
1267
1260
|
end
|
1268
1261
|
else
|
1269
1262
|
@bps[bp.key] = bp
|
@@ -1320,7 +1313,7 @@ module DEBUGGER__
|
|
1320
1313
|
when /\A(.+)[:\s+](\d+)\z/
|
1321
1314
|
add_line_breakpoint $1, $2.to_i, cond: cond, command: cmd
|
1322
1315
|
when /\A(.+)([\.\#])(.+)\z/
|
1323
|
-
|
1316
|
+
request_tc [:breakpoint, :method, $1, $2, $3, cond, cmd, path]
|
1324
1317
|
return :noretry
|
1325
1318
|
when nil
|
1326
1319
|
add_check_breakpoint cond, path, cmd
|
@@ -1347,11 +1340,11 @@ module DEBUGGER__
|
|
1347
1340
|
cmd = ['watch', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
1348
1341
|
path = Regexp.compile(expr[:path]) if expr[:path]
|
1349
1342
|
|
1350
|
-
|
1343
|
+
request_tc [:breakpoint, :watch, expr[:sig], cond, cmd, path]
|
1351
1344
|
end
|
1352
1345
|
|
1353
|
-
def add_catch_breakpoint pat
|
1354
|
-
bp = CatchBreakpoint.new(pat)
|
1346
|
+
def add_catch_breakpoint pat, cond: nil
|
1347
|
+
bp = CatchBreakpoint.new(pat, cond: cond)
|
1355
1348
|
add_bp bp
|
1356
1349
|
end
|
1357
1350
|
|
@@ -1369,15 +1362,34 @@ module DEBUGGER__
|
|
1369
1362
|
@ui.puts e.message
|
1370
1363
|
end
|
1371
1364
|
|
1372
|
-
def
|
1373
|
-
path = resolve_path(path)
|
1365
|
+
def clear_breakpoints(&condition)
|
1374
1366
|
@bps.delete_if do |k, bp|
|
1375
|
-
if
|
1367
|
+
if condition.call(k, bp)
|
1376
1368
|
bp.delete
|
1369
|
+
true
|
1377
1370
|
end
|
1378
1371
|
end
|
1379
1372
|
end
|
1380
1373
|
|
1374
|
+
def clear_line_breakpoints path
|
1375
|
+
path = resolve_path(path)
|
1376
|
+
clear_breakpoints do |k, bp|
|
1377
|
+
bp.is_a?(LineBreakpoint) && DEBUGGER__.compare_path(k.first, path)
|
1378
|
+
end
|
1379
|
+
rescue Errno::ENOENT
|
1380
|
+
# just ignore
|
1381
|
+
end
|
1382
|
+
|
1383
|
+
def clear_catch_breakpoints *exception_names
|
1384
|
+
clear_breakpoints do |k, bp|
|
1385
|
+
bp.is_a?(CatchBreakpoint) && exception_names.include?(k[1])
|
1386
|
+
end
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
def clear_all_breakpoints
|
1390
|
+
clear_breakpoints{true}
|
1391
|
+
end
|
1392
|
+
|
1381
1393
|
def add_iseq_breakpoint iseq, **kw
|
1382
1394
|
bp = ISeqBreakpoint.new(iseq, [:line], **kw)
|
1383
1395
|
add_bp bp
|
@@ -1568,7 +1580,7 @@ module DEBUGGER__
|
|
1568
1580
|
DEBUGGER__.info "Leave subsession (nested #{@subsession_stack.size})"
|
1569
1581
|
end
|
1570
1582
|
|
1571
|
-
|
1583
|
+
request_tc type if type
|
1572
1584
|
@tc = nil
|
1573
1585
|
rescue Exception => e
|
1574
1586
|
STDERR.puts PP.pp([e, e.backtrace], ''.dup)
|
@@ -1583,7 +1595,9 @@ module DEBUGGER__
|
|
1583
1595
|
|
1584
1596
|
def on_load iseq, src
|
1585
1597
|
DEBUGGER__.info "Load #{iseq.absolute_path || iseq.path}"
|
1586
|
-
|
1598
|
+
|
1599
|
+
file_path, reloaded = @sr.add(iseq, src)
|
1600
|
+
@ui.event :load, file_path, reloaded
|
1587
1601
|
|
1588
1602
|
pending_line_breakpoints = @bps.find_all do |key, bp|
|
1589
1603
|
LineBreakpoint === bp && !bp.iseq
|
@@ -1591,7 +1605,18 @@ module DEBUGGER__
|
|
1591
1605
|
|
1592
1606
|
pending_line_breakpoints.each do |_key, bp|
|
1593
1607
|
if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
|
1594
|
-
bp.try_activate
|
1608
|
+
bp.try_activate iseq
|
1609
|
+
end
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
if reloaded
|
1613
|
+
@bps.find_all do |key, bp|
|
1614
|
+
LineBreakpoint === bp && DEBUGGER__.compare_path(bp.path, file_path)
|
1615
|
+
end.each do |_key, bp|
|
1616
|
+
@bps.delete bp.key # to allow duplicate
|
1617
|
+
if nbp = LineBreakpoint.copy(bp, iseq)
|
1618
|
+
add_bp nbp
|
1619
|
+
end
|
1595
1620
|
end
|
1596
1621
|
end
|
1597
1622
|
end
|
@@ -1618,7 +1643,7 @@ module DEBUGGER__
|
|
1618
1643
|
b = tp.binding
|
1619
1644
|
if var_name = b.local_variables.first
|
1620
1645
|
mid = b.local_variable_get(var_name)
|
1621
|
-
|
1646
|
+
resolved = true
|
1622
1647
|
|
1623
1648
|
@bps.each{|k, bp|
|
1624
1649
|
case bp
|
@@ -1629,15 +1654,53 @@ module DEBUGGER__
|
|
1629
1654
|
end
|
1630
1655
|
end
|
1631
1656
|
|
1632
|
-
|
1657
|
+
resolved = false if !bp.enabled?
|
1633
1658
|
end
|
1634
1659
|
}
|
1635
|
-
|
1636
|
-
|
1660
|
+
|
1661
|
+
if resolved
|
1662
|
+
Session.deactivate_method_added_trackers
|
1663
|
+
end
|
1664
|
+
|
1665
|
+
case mid
|
1666
|
+
when :method_added, :singleton_method_added
|
1667
|
+
Session.create_method_added_tracker(tp.self, mid)
|
1668
|
+
Session.create_method_added_tracker unless resolved
|
1637
1669
|
end
|
1638
1670
|
end
|
1639
1671
|
end
|
1640
1672
|
|
1673
|
+
class ::Module
|
1674
|
+
undef method_added
|
1675
|
+
def method_added mid; end
|
1676
|
+
def singleton_method_added mid; end
|
1677
|
+
end
|
1678
|
+
|
1679
|
+
def self.create_method_added_tracker mod, method_added_id, method_accessor = :method
|
1680
|
+
m = mod.__send__(method_accessor, method_added_id)
|
1681
|
+
METHOD_ADDED_TRACKERS[m] = TracePoint.new(:call) do |tp|
|
1682
|
+
SESSION.method_added tp
|
1683
|
+
end
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
def self.activate_method_added_trackers
|
1687
|
+
METHOD_ADDED_TRACKERS.each do |m, tp|
|
1688
|
+
tp.enable(target: m) unless tp.enabled?
|
1689
|
+
rescue ArgumentError
|
1690
|
+
DEBUGGER__.warn "Methods defined under #{m.owner} can not track by the debugger."
|
1691
|
+
end
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
def self.deactivate_method_added_trackers
|
1695
|
+
METHOD_ADDED_TRACKERS.each do |m, tp|
|
1696
|
+
tp.disable if tp.enabled?
|
1697
|
+
end
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
METHOD_ADDED_TRACKERS = Hash.new
|
1701
|
+
create_method_added_tracker Module, :method_added, :instance_method
|
1702
|
+
create_method_added_tracker Module, :singleton_method_added, :instance_method
|
1703
|
+
|
1641
1704
|
def width
|
1642
1705
|
@ui.width
|
1643
1706
|
end
|
@@ -2051,34 +2114,53 @@ module DEBUGGER__
|
|
2051
2114
|
end
|
2052
2115
|
end
|
2053
2116
|
|
2054
|
-
|
2055
|
-
|
2056
|
-
|
2057
|
-
def singleton_method_added mid; end
|
2058
|
-
end
|
2117
|
+
# Inspector
|
2118
|
+
|
2119
|
+
SHORT_INSPECT_LENGTH = 40
|
2059
2120
|
|
2060
|
-
|
2061
|
-
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2121
|
+
class LimitedPP
|
2122
|
+
def self.pp(obj, max=80)
|
2123
|
+
out = self.new(max)
|
2124
|
+
catch out do
|
2125
|
+
PP.singleline_pp(obj, out)
|
2126
|
+
end
|
2127
|
+
out.buf
|
2065
2128
|
end
|
2066
|
-
end
|
2067
2129
|
|
2068
|
-
|
2130
|
+
attr_reader :buf
|
2069
2131
|
|
2070
|
-
|
2132
|
+
def initialize max
|
2133
|
+
@max = max
|
2134
|
+
@cnt = 0
|
2135
|
+
@buf = String.new
|
2136
|
+
end
|
2071
2137
|
|
2072
|
-
|
2073
|
-
|
2138
|
+
def <<(other)
|
2139
|
+
@buf << other
|
2074
2140
|
|
2075
|
-
|
2076
|
-
|
2141
|
+
if @buf.size >= @max
|
2142
|
+
@buf = @buf[0..@max] + '...'
|
2143
|
+
throw self
|
2144
|
+
end
|
2145
|
+
end
|
2146
|
+
end
|
2147
|
+
|
2148
|
+
def self.safe_inspect obj, max_length: SHORT_INSPECT_LENGTH, short: false
|
2149
|
+
if short
|
2150
|
+
LimitedPP.pp(obj, max_length)
|
2151
|
+
else
|
2152
|
+
obj.inspect
|
2153
|
+
end
|
2154
|
+
rescue NoMethodError => e
|
2155
|
+
klass, oid = M_CLASS.bind_call(obj), M_OBJECT_ID.bind_call(obj)
|
2156
|
+
if obj == (r = e.receiver)
|
2157
|
+
"<\##{klass.name}#{oid} does not have \#inspect>"
|
2077
2158
|
else
|
2078
|
-
|
2159
|
+
rklass, roid = M_CLASS.bind_call(r), M_OBJECT_ID.bind_call(r)
|
2160
|
+
"<\##{klass.name}:#{roid} contains <\##{rklass}:#{roid} and it does not have #inspect>"
|
2079
2161
|
end
|
2080
2162
|
rescue Exception => e
|
2081
|
-
|
2163
|
+
"<#inspect raises #{e.inspect}>"
|
2082
2164
|
end
|
2083
2165
|
|
2084
2166
|
def self.warn msg
|
@@ -2089,18 +2171,27 @@ module DEBUGGER__
|
|
2089
2171
|
log :INFO, msg
|
2090
2172
|
end
|
2091
2173
|
|
2092
|
-
def self.
|
2093
|
-
@logfile = STDERR unless defined? @logfile
|
2094
|
-
|
2174
|
+
def self.check_loglevel level
|
2095
2175
|
lv = LOG_LEVELS[level]
|
2096
|
-
config_lv = LOG_LEVELS[CONFIG[:log_level]
|
2176
|
+
config_lv = LOG_LEVELS[CONFIG[:log_level]]
|
2177
|
+
lv <= config_lv
|
2178
|
+
end
|
2097
2179
|
|
2098
|
-
|
2099
|
-
|
2100
|
-
|
2180
|
+
def self.debug(&b)
|
2181
|
+
if check_loglevel :DEBUG
|
2182
|
+
log :DEBUG, b.call
|
2101
2183
|
end
|
2184
|
+
end
|
2185
|
+
|
2186
|
+
def self.log level, msg
|
2187
|
+
if check_loglevel level
|
2188
|
+
@logfile = STDERR unless defined? @logfile
|
2189
|
+
|
2190
|
+
if defined? SESSION
|
2191
|
+
pi = SESSION.process_info
|
2192
|
+
process_info = pi ? "[#{pi}]" : nil
|
2193
|
+
end
|
2102
2194
|
|
2103
|
-
if lv <= config_lv
|
2104
2195
|
if level == :WARN
|
2105
2196
|
# :WARN on debugger is general information
|
2106
2197
|
@logfile.puts "DEBUGGER#{process_info}: #{msg}"
|
@@ -2137,7 +2228,7 @@ module DEBUGGER__
|
|
2137
2228
|
module ForkInterceptor
|
2138
2229
|
if Process.respond_to? :_fork
|
2139
2230
|
def _fork
|
2140
|
-
return
|
2231
|
+
return super unless defined?(SESSION) && SESSION.active?
|
2141
2232
|
|
2142
2233
|
parent_hook, child_hook = __fork_setup_for_debugger
|
2143
2234
|
|
@@ -2153,7 +2244,7 @@ module DEBUGGER__
|
|
2153
2244
|
end
|
2154
2245
|
else
|
2155
2246
|
def fork(&given_block)
|
2156
|
-
return
|
2247
|
+
return super unless defined?(SESSION) && SESSION.active?
|
2157
2248
|
parent_hook, child_hook = __fork_setup_for_debugger
|
2158
2249
|
|
2159
2250
|
if given_block
|
@@ -2178,12 +2269,10 @@ module DEBUGGER__
|
|
2178
2269
|
end
|
2179
2270
|
|
2180
2271
|
private def __fork_setup_for_debugger
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
fork_mode = :both
|
2186
|
-
end
|
2272
|
+
fork_mode = CONFIG[:fork_mode]
|
2273
|
+
|
2274
|
+
if fork_mode == :both && CONFIG[:parent_on_fork]
|
2275
|
+
fork_mode = :parent
|
2187
2276
|
end
|
2188
2277
|
|
2189
2278
|
parent_pid = Process.pid
|
@@ -2310,3 +2399,12 @@ class Binding
|
|
2310
2399
|
alias break debugger
|
2311
2400
|
alias b debugger
|
2312
2401
|
end
|
2402
|
+
|
2403
|
+
# for Ruby 2.6 compatibility
|
2404
|
+
unless method(:p).unbind.respond_to? :bind_call
|
2405
|
+
class UnboundMethod
|
2406
|
+
def bind_call(obj, *args)
|
2407
|
+
self.bind(obj).call(*args)
|
2408
|
+
end
|
2409
|
+
end
|
2410
|
+
end
|