debug 1.4.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +195 -3
- data/Gemfile +1 -0
- data/README.md +55 -32
- data/Rakefile +28 -10
- data/debug.gemspec +7 -5
- data/exe/rdbg +7 -3
- data/ext/debug/debug.c +76 -14
- data/ext/debug/extconf.rb +22 -0
- data/lib/debug/breakpoint.rb +90 -66
- data/lib/debug/client.rb +21 -5
- data/lib/debug/config.rb +55 -24
- data/lib/debug/console.rb +43 -16
- data/lib/debug/frame_info.rb +32 -26
- data/lib/debug/local.rb +1 -1
- data/lib/debug/server.rb +105 -40
- data/lib/debug/server_cdp.rb +373 -152
- data/lib/debug/server_dap.rb +273 -170
- data/lib/debug/session.rb +450 -236
- data/lib/debug/source_repository.rb +104 -51
- data/lib/debug/thread_client.rb +252 -103
- data/lib/debug/tracer.rb +7 -12
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +34 -14
- metadata +6 -16
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -24
- data/.github/ISSUE_TEMPLATE/custom.md +0 -10
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- data/.github/pull_request_template.md +0 -9
- data/.github/workflows/ruby.yml +0 -34
- data/.gitignore +0 -12
- data/bin/console +0 -14
- data/bin/gentest +0 -30
- data/bin/setup +0 -8
- data/lib/debug/bp.vim +0 -68
data/lib/debug/thread_client.rb
CHANGED
@@ -6,11 +6,32 @@ require 'pp'
|
|
6
6
|
require_relative 'color'
|
7
7
|
|
8
8
|
module DEBUGGER__
|
9
|
+
M_INSTANCE_VARIABLES = method(:instance_variables).unbind
|
10
|
+
M_INSTANCE_VARIABLE_GET = method(:instance_variable_get).unbind
|
11
|
+
M_CLASS = method(:class).unbind
|
12
|
+
M_SINGLETON_CLASS = method(:singleton_class).unbind
|
13
|
+
M_KIND_OF_P = method(:kind_of?).unbind
|
14
|
+
M_RESPOND_TO_P = method(:respond_to?).unbind
|
15
|
+
M_METHOD = method(:method).unbind
|
16
|
+
M_OBJECT_ID = method(:object_id).unbind
|
17
|
+
|
9
18
|
module SkipPathHelper
|
10
19
|
def skip_path?(path)
|
20
|
+
!path ||
|
21
|
+
CONFIG.skip? ||
|
22
|
+
ThreadClient.current.management? ||
|
23
|
+
skip_internal_path?(path) ||
|
24
|
+
skip_config_skip_path?(path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def skip_config_skip_path?(path)
|
11
28
|
(skip_paths = CONFIG[:skip_path]) && skip_paths.any?{|skip_path| path.match?(skip_path)}
|
12
29
|
end
|
13
30
|
|
31
|
+
def skip_internal_path?(path)
|
32
|
+
path.start_with?(__dir__) || path.start_with?('<internal:')
|
33
|
+
end
|
34
|
+
|
14
35
|
def skip_location?(loc)
|
15
36
|
loc_path = loc.absolute_path || "!eval:#{loc.path}"
|
16
37
|
skip_path?(loc_path)
|
@@ -30,7 +51,11 @@ module DEBUGGER__
|
|
30
51
|
include Color
|
31
52
|
include SkipPathHelper
|
32
53
|
|
33
|
-
attr_reader :
|
54
|
+
attr_reader :thread, :id, :recorder, :check_bp_fulfillment_map
|
55
|
+
|
56
|
+
def location
|
57
|
+
current_frame&.location
|
58
|
+
end
|
34
59
|
|
35
60
|
def assemble_arguments(args)
|
36
61
|
args.map do |arg|
|
@@ -42,7 +67,8 @@ module DEBUGGER__
|
|
42
67
|
call_identifier_str =
|
43
68
|
case frame.frame_type
|
44
69
|
when :block
|
45
|
-
level, block_loc
|
70
|
+
level, block_loc = frame.block_identifier
|
71
|
+
args = frame.parameters_info
|
46
72
|
|
47
73
|
if !args.empty?
|
48
74
|
args_str = " {|#{assemble_arguments(args)}|}"
|
@@ -50,7 +76,8 @@ module DEBUGGER__
|
|
50
76
|
|
51
77
|
"#{colorize_blue("block")}#{args_str} in #{colorize_blue(block_loc + level)}"
|
52
78
|
when :method
|
53
|
-
ci
|
79
|
+
ci = frame.method_identifier
|
80
|
+
args = frame.parameters_info
|
54
81
|
|
55
82
|
if !args.empty?
|
56
83
|
args_str = "(#{assemble_arguments(args)})"
|
@@ -87,6 +114,9 @@ module DEBUGGER__
|
|
87
114
|
@obj_map = {} # { object_id => obj } for CDP
|
88
115
|
@recorder = nil
|
89
116
|
@mode = :waiting
|
117
|
+
@current_frame_index = 0
|
118
|
+
# every thread should maintain its own CheckBreakpoint fulfillment state
|
119
|
+
@check_bp_fulfillment_map = {} # { check_bp => boolean }
|
90
120
|
set_mode :running
|
91
121
|
thr.instance_variable_set(:@__thread_client_id, id)
|
92
122
|
|
@@ -106,6 +136,7 @@ module DEBUGGER__
|
|
106
136
|
end
|
107
137
|
|
108
138
|
def set_mode mode
|
139
|
+
debug_mode(@mode, mode)
|
109
140
|
# STDERR.puts "#{@mode} => #{mode} @ #{caller.inspect}"
|
110
141
|
# pp caller
|
111
142
|
|
@@ -149,14 +180,7 @@ module DEBUGGER__
|
|
149
180
|
end
|
150
181
|
|
151
182
|
def to_s
|
152
|
-
|
153
|
-
|
154
|
-
if loc
|
155
|
-
str = "(#{@thread.name || @thread.status})@#{loc}"
|
156
|
-
else
|
157
|
-
str = "(#{@thread.name || @thread.status})@#{@thread.to_s}"
|
158
|
-
end
|
159
|
-
|
183
|
+
str = "(#{@thread.name || @thread.status})@#{current_frame&.location || @thread.to_s}"
|
160
184
|
str += " (not under control)" unless self.waiting?
|
161
185
|
str
|
162
186
|
end
|
@@ -176,6 +200,7 @@ module DEBUGGER__
|
|
176
200
|
end
|
177
201
|
|
178
202
|
def << req
|
203
|
+
debug_cmd(req)
|
179
204
|
@q_cmd << req
|
180
205
|
end
|
181
206
|
|
@@ -186,6 +211,7 @@ module DEBUGGER__
|
|
186
211
|
end
|
187
212
|
|
188
213
|
def event! ev, *args
|
214
|
+
debug_event(ev, args)
|
189
215
|
@q_evt << [self, @output, ev, generate_info, *args]
|
190
216
|
@output = []
|
191
217
|
end
|
@@ -231,6 +257,7 @@ module DEBUGGER__
|
|
231
257
|
|
232
258
|
def suspend event, tp = nil, bp: nil, sig: nil, postmortem_frames: nil, replay_frames: nil, postmortem_exc: nil
|
233
259
|
return if management?
|
260
|
+
debug_suspend(event)
|
234
261
|
|
235
262
|
@current_frame_index = 0
|
236
263
|
|
@@ -246,7 +273,6 @@ module DEBUGGER__
|
|
246
273
|
|
247
274
|
cf = @target_frames.first
|
248
275
|
if cf
|
249
|
-
@location = cf.location
|
250
276
|
case event
|
251
277
|
when :return, :b_return, :c_return
|
252
278
|
cf.has_return_value = true
|
@@ -266,7 +292,7 @@ module DEBUGGER__
|
|
266
292
|
|
267
293
|
if event != :pause
|
268
294
|
show_src
|
269
|
-
show_frames CONFIG[:show_frames]
|
295
|
+
show_frames CONFIG[:show_frames]
|
270
296
|
|
271
297
|
set_mode :waiting
|
272
298
|
|
@@ -339,9 +365,45 @@ module DEBUGGER__
|
|
339
365
|
|
340
366
|
## cmd helpers
|
341
367
|
|
342
|
-
|
343
|
-
|
344
|
-
|
368
|
+
if TracePoint.respond_to? :allow_reentry
|
369
|
+
def tp_allow_reentry
|
370
|
+
TracePoint.allow_reentry do
|
371
|
+
yield
|
372
|
+
end
|
373
|
+
rescue RuntimeError => e
|
374
|
+
# on the postmortem mode, it is not stopped in TracePoint
|
375
|
+
if e.message == 'No need to allow reentrance.'
|
376
|
+
yield
|
377
|
+
else
|
378
|
+
raise
|
379
|
+
end
|
380
|
+
end
|
381
|
+
else
|
382
|
+
def tp_allow_reentry
|
383
|
+
yield
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def frame_eval_core src, b
|
388
|
+
saved_target_frames = @target_frames
|
389
|
+
saved_current_frame_index = @current_frame_index
|
390
|
+
|
391
|
+
if b
|
392
|
+
f, _l = b.source_location
|
393
|
+
|
394
|
+
tp_allow_reentry do
|
395
|
+
b.eval(src, "(rdbg)/#{f}")
|
396
|
+
end
|
397
|
+
else
|
398
|
+
frame_self = current_frame.self
|
399
|
+
|
400
|
+
tp_allow_reentry do
|
401
|
+
frame_self.instance_eval(src)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
ensure
|
405
|
+
@target_frames = saved_target_frames
|
406
|
+
@current_frame_index = saved_current_frame_index
|
345
407
|
end
|
346
408
|
|
347
409
|
SPECIAL_LOCAL_VARS = [
|
@@ -358,16 +420,13 @@ module DEBUGGER__
|
|
358
420
|
b.local_variable_set(name, var) if /\%/ !~ name
|
359
421
|
end
|
360
422
|
|
361
|
-
result =
|
362
|
-
|
363
|
-
b.eval(src, "(rdbg)/#{f}")
|
364
|
-
else
|
365
|
-
frame_self = current_frame.self
|
366
|
-
instance_eval_for_cmethod(frame_self, src)
|
367
|
-
end
|
423
|
+
result = frame_eval_core(src, b)
|
424
|
+
|
368
425
|
@success_last_eval = true
|
369
426
|
result
|
370
427
|
|
428
|
+
rescue SystemExit
|
429
|
+
raise
|
371
430
|
rescue Exception => e
|
372
431
|
return yield(e) if block_given?
|
373
432
|
|
@@ -380,65 +439,97 @@ module DEBUGGER__
|
|
380
439
|
raise if re_raise
|
381
440
|
end
|
382
441
|
|
383
|
-
def
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
"#{cur}#{line} #{e}"
|
397
|
-
end
|
442
|
+
def get_src(frame,
|
443
|
+
max_lines:,
|
444
|
+
start_line: nil,
|
445
|
+
end_line: nil,
|
446
|
+
dir: +1)
|
447
|
+
if file_lines = frame.file_lines
|
448
|
+
frame_line = frame.location.lineno - 1
|
449
|
+
|
450
|
+
lines = file_lines.map.with_index do |e, i|
|
451
|
+
cur = i == frame_line ? '=>' : ' '
|
452
|
+
line = colorize_dim('%4d|' % (i+1))
|
453
|
+
"#{cur}#{line} #{e}"
|
454
|
+
end
|
398
455
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
else
|
404
|
-
end_line = frame.show_line - max_lines
|
405
|
-
start_line = [end_line - max_lines, 0].max
|
406
|
-
end
|
456
|
+
unless start_line
|
457
|
+
if frame.show_line
|
458
|
+
if dir > 0
|
459
|
+
start_line = frame.show_line
|
407
460
|
else
|
408
|
-
|
461
|
+
end_line = frame.show_line - max_lines
|
462
|
+
start_line = [end_line - max_lines, 0].max
|
409
463
|
end
|
464
|
+
else
|
465
|
+
start_line = [frame_line - max_lines/2, 0].max
|
410
466
|
end
|
467
|
+
end
|
411
468
|
|
412
|
-
|
413
|
-
|
414
|
-
|
469
|
+
unless end_line
|
470
|
+
end_line = [start_line + max_lines, lines.size].min
|
471
|
+
end
|
415
472
|
|
473
|
+
if start_line != end_line && max_lines
|
474
|
+
[start_line, end_line, lines]
|
475
|
+
end
|
476
|
+
else # no file lines
|
477
|
+
nil
|
478
|
+
end
|
479
|
+
rescue Exception => e
|
480
|
+
p e
|
481
|
+
pp e.backtrace
|
482
|
+
exit!
|
483
|
+
end
|
484
|
+
|
485
|
+
def show_src(frame_index: @current_frame_index, update_line: false, max_lines: CONFIG[:show_src_lines], **options)
|
486
|
+
if frame = get_frame(frame_index)
|
487
|
+
start_line, end_line, lines = *get_src(frame, max_lines: max_lines, **options)
|
488
|
+
|
489
|
+
if start_line
|
416
490
|
if update_line
|
417
491
|
frame.show_line = end_line
|
418
492
|
end
|
419
493
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
end
|
424
|
-
else # no file lines
|
494
|
+
puts "[#{start_line+1}, #{end_line}] in #{frame.pretty_path}" if !update_line && max_lines != 1
|
495
|
+
puts lines[start_line...end_line]
|
496
|
+
else
|
425
497
|
puts "# No sourcefile available for #{frame.path}"
|
426
498
|
end
|
427
499
|
end
|
428
|
-
rescue Exception => e
|
429
|
-
p e
|
430
|
-
pp e.backtrace
|
431
|
-
exit!
|
432
500
|
end
|
433
501
|
|
434
502
|
def current_frame
|
503
|
+
get_frame(@current_frame_index)
|
504
|
+
end
|
505
|
+
|
506
|
+
def get_frame(index)
|
435
507
|
if @target_frames
|
436
|
-
@target_frames[
|
508
|
+
@target_frames[index]
|
437
509
|
else
|
438
510
|
nil
|
439
511
|
end
|
440
512
|
end
|
441
513
|
|
514
|
+
def collect_locals(frame)
|
515
|
+
locals = []
|
516
|
+
|
517
|
+
if s = frame&.self
|
518
|
+
locals << ["%self", s]
|
519
|
+
end
|
520
|
+
special_local_variables frame do |name, val|
|
521
|
+
locals << [name, val]
|
522
|
+
end
|
523
|
+
|
524
|
+
if vars = frame&.local_variables
|
525
|
+
vars.each{|var, val|
|
526
|
+
locals << [var, val]
|
527
|
+
}
|
528
|
+
end
|
529
|
+
|
530
|
+
locals
|
531
|
+
end
|
532
|
+
|
442
533
|
## cmd: show
|
443
534
|
|
444
535
|
def special_local_variables frame
|
@@ -450,24 +541,15 @@ module DEBUGGER__
|
|
450
541
|
end
|
451
542
|
|
452
543
|
def show_locals pat
|
453
|
-
|
454
|
-
puts_variable_info
|
455
|
-
end
|
456
|
-
special_local_variables current_frame do |name, val|
|
457
|
-
puts_variable_info name, val, pat
|
458
|
-
end
|
459
|
-
|
460
|
-
if vars = current_frame&.local_variables
|
461
|
-
vars.each{|var, val|
|
462
|
-
puts_variable_info var, val, pat
|
463
|
-
}
|
544
|
+
collect_locals(current_frame).each do |var, val|
|
545
|
+
puts_variable_info(var, val, pat)
|
464
546
|
end
|
465
547
|
end
|
466
548
|
|
467
549
|
def show_ivars pat
|
468
550
|
if s = current_frame&.self
|
469
|
-
s.
|
470
|
-
value =
|
551
|
+
M_INSTANCE_VARIABLES.bind_call(s).sort.each{|iv|
|
552
|
+
value = M_INSTANCE_VARIABLE_GET.bind_call(s, iv)
|
471
553
|
puts_variable_info iv, value, pat
|
472
554
|
}
|
473
555
|
end
|
@@ -476,10 +558,10 @@ module DEBUGGER__
|
|
476
558
|
def show_consts pat, only_self: false
|
477
559
|
if s = current_frame&.self
|
478
560
|
cs = {}
|
479
|
-
if s
|
561
|
+
if M_KIND_OF_P.bind_call(s, Module)
|
480
562
|
cs[s] = :self
|
481
563
|
else
|
482
|
-
s = s
|
564
|
+
s = M_CLASS.bind_call(s)
|
483
565
|
cs[s] = :self unless only_self
|
484
566
|
end
|
485
567
|
|
@@ -517,7 +599,7 @@ module DEBUGGER__
|
|
517
599
|
return if pat && pat !~ label
|
518
600
|
|
519
601
|
begin
|
520
|
-
inspected = obj
|
602
|
+
inspected = DEBUGGER__.safe_inspect(obj)
|
521
603
|
rescue Exception => e
|
522
604
|
inspected = e.inspect
|
523
605
|
end
|
@@ -526,28 +608,32 @@ module DEBUGGER__
|
|
526
608
|
w = SESSION::width
|
527
609
|
|
528
610
|
if mono_info.length >= w
|
529
|
-
|
611
|
+
maximum_value_width = w - "#{label} = ".length
|
612
|
+
valstr = truncate(inspected, width: maximum_value_width)
|
530
613
|
else
|
531
614
|
valstr = colored_inspect(obj, width: 2 ** 30)
|
532
615
|
valstr = inspected if valstr.lines.size > 1
|
533
|
-
info = "#{colorize_cyan(label)} = #{valstr}"
|
534
616
|
end
|
535
617
|
|
618
|
+
info = "#{colorize_cyan(label)} = #{valstr}"
|
619
|
+
|
536
620
|
puts info
|
537
621
|
end
|
538
622
|
|
539
623
|
def truncate(string, width:)
|
540
|
-
|
541
|
-
|
542
|
-
|
624
|
+
if string.start_with?("#<")
|
625
|
+
string[0 .. (width-5)] + '...>'
|
626
|
+
else
|
627
|
+
string[0 .. (width-4)] + '...'
|
628
|
+
end
|
543
629
|
end
|
544
630
|
|
545
631
|
### cmd: show edit
|
546
632
|
|
547
633
|
def show_by_editor path = nil
|
548
634
|
unless path
|
549
|
-
if
|
550
|
-
path =
|
635
|
+
if current_frame
|
636
|
+
path = current_frame.path
|
551
637
|
else
|
552
638
|
return # can't get path
|
553
639
|
end
|
@@ -572,15 +658,11 @@ module DEBUGGER__
|
|
572
658
|
if @target_frames && (max ||= @target_frames.size) > 0
|
573
659
|
frames = []
|
574
660
|
@target_frames.each_with_index{|f, i|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
when Regexp
|
581
|
-
f.location_str.match?(pat)
|
582
|
-
end
|
583
|
-
}
|
661
|
+
# we need to use FrameInfo#matchable_location because #location_str is for display
|
662
|
+
# and it may change based on configs (e.g. use_short_path)
|
663
|
+
next if pattern && !(f.name.match?(pattern) || f.matchable_location.match?(pattern))
|
664
|
+
# avoid using skip_path? because we still want to display internal frames
|
665
|
+
next if skip_config_skip_path?(f.matchable_location)
|
584
666
|
|
585
667
|
frames << [i, f]
|
586
668
|
}
|
@@ -617,18 +699,25 @@ module DEBUGGER__
|
|
617
699
|
o = Output.new(@output)
|
618
700
|
|
619
701
|
locals = current_frame&.local_variables
|
620
|
-
klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
|
621
702
|
|
622
|
-
|
703
|
+
klass = M_CLASS.bind_call(obj)
|
704
|
+
klass = obj if Class == klass || Module == klass
|
705
|
+
|
706
|
+
o.dump("constants", obj.constants) if M_RESPOND_TO_P.bind_call(obj, :constants)
|
623
707
|
outline_method(o, klass, obj)
|
624
|
-
o.dump("instance variables", obj
|
708
|
+
o.dump("instance variables", M_INSTANCE_VARIABLES.bind_call(obj))
|
625
709
|
o.dump("class variables", klass.class_variables)
|
626
710
|
o.dump("locals", locals.keys) if locals
|
627
711
|
end
|
628
712
|
end
|
629
713
|
|
630
714
|
def outline_method(o, klass, obj)
|
631
|
-
|
715
|
+
begin
|
716
|
+
singleton_class = M_SINGLETON_CLASS.bind_call(obj)
|
717
|
+
rescue TypeError
|
718
|
+
singleton_class = nil
|
719
|
+
end
|
720
|
+
|
632
721
|
maps = class_method_map((singleton_class || klass).ancestors)
|
633
722
|
maps.each do |mod, methods|
|
634
723
|
name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
|
@@ -648,6 +737,23 @@ module DEBUGGER__
|
|
648
737
|
|
649
738
|
## cmd: breakpoint
|
650
739
|
|
740
|
+
# TODO: support non-ASCII Constant name
|
741
|
+
def constant_name? name
|
742
|
+
case name
|
743
|
+
when /\A::\b/
|
744
|
+
constant_name? $~.post_match
|
745
|
+
when /\A[A-Z]\w*/
|
746
|
+
post = $~.post_match
|
747
|
+
if post.empty?
|
748
|
+
true
|
749
|
+
else
|
750
|
+
constant_name? post
|
751
|
+
end
|
752
|
+
else
|
753
|
+
false
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
651
757
|
def make_breakpoint args
|
652
758
|
case args.first
|
653
759
|
when :method
|
@@ -655,9 +761,24 @@ module DEBUGGER__
|
|
655
761
|
bp = MethodBreakpoint.new(current_frame.eval_binding, klass_name, op, method_name, cond: cond, command: cmd, path: path)
|
656
762
|
begin
|
657
763
|
bp.enable
|
764
|
+
rescue NameError => e
|
765
|
+
if bp.klass
|
766
|
+
puts "Unknown method name: \"#{e.name}\""
|
767
|
+
else
|
768
|
+
# klass_name can not be evaluated
|
769
|
+
if constant_name? klass_name
|
770
|
+
puts "Unknown constant name: \"#{e.name}\""
|
771
|
+
else
|
772
|
+
# only Class name is allowed
|
773
|
+
puts "Not a constant name: \"#{klass_name}\""
|
774
|
+
bp = nil
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
Session.activate_method_added_trackers if bp
|
658
779
|
rescue Exception => e
|
659
|
-
puts e.
|
660
|
-
|
780
|
+
puts e.inspect
|
781
|
+
bp = nil
|
661
782
|
end
|
662
783
|
|
663
784
|
bp
|
@@ -853,6 +974,7 @@ module DEBUGGER__
|
|
853
974
|
else
|
854
975
|
raise "unsupported frame operation: #{arg.inspect}"
|
855
976
|
end
|
977
|
+
|
856
978
|
event! :result, nil
|
857
979
|
|
858
980
|
when :show
|
@@ -929,7 +1051,7 @@ module DEBUGGER__
|
|
929
1051
|
begin
|
930
1052
|
obj = frame_eval args.shift, re_raise: true
|
931
1053
|
opt = args.shift
|
932
|
-
obj_inspect = obj
|
1054
|
+
obj_inspect = DEBUGGER__.safe_inspect(obj)
|
933
1055
|
|
934
1056
|
width = 50
|
935
1057
|
|
@@ -937,7 +1059,7 @@ module DEBUGGER__
|
|
937
1059
|
obj_inspect = truncate(obj_inspect, width: width)
|
938
1060
|
end
|
939
1061
|
|
940
|
-
event! :result, :trace_pass, obj
|
1062
|
+
event! :result, :trace_pass, M_OBJECT_ID.bind_call(obj), obj_inspect, opt
|
941
1063
|
rescue => e
|
942
1064
|
puts e.message
|
943
1065
|
event! :result, nil
|
@@ -954,8 +1076,8 @@ module DEBUGGER__
|
|
954
1076
|
# enable recording
|
955
1077
|
if !@recorder
|
956
1078
|
@recorder = Recorder.new
|
957
|
-
@recorder.enable
|
958
1079
|
end
|
1080
|
+
@recorder.enable
|
959
1081
|
when :off
|
960
1082
|
if @recorder&.enabled?
|
961
1083
|
@recorder.disable
|
@@ -987,6 +1109,33 @@ module DEBUGGER__
|
|
987
1109
|
raise
|
988
1110
|
end
|
989
1111
|
|
1112
|
+
def debug_event(ev, args)
|
1113
|
+
DEBUGGER__.debug{
|
1114
|
+
args = args.map { |arg| DEBUGGER__.safe_inspect(arg) }
|
1115
|
+
"#{inspect} sends Event { type: #{ev.inspect}, args: #{args} } to Session"
|
1116
|
+
}
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
def debug_mode(old_mode, new_mode)
|
1120
|
+
DEBUGGER__.debug{
|
1121
|
+
"#{inspect} changes mode (#{old_mode} -> #{new_mode})"
|
1122
|
+
}
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
def debug_cmd(cmds)
|
1126
|
+
DEBUGGER__.debug{
|
1127
|
+
cmd, *args = *cmds
|
1128
|
+
args = args.map { |arg| DEBUGGER__.safe_inspect(arg) }
|
1129
|
+
"#{inspect} receives Cmd { type: #{cmd.inspect}, args: #{args} } from Session"
|
1130
|
+
}
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
def debug_suspend(event)
|
1134
|
+
DEBUGGER__.debug{
|
1135
|
+
"#{inspect} is suspended for #{event.inspect}"
|
1136
|
+
}
|
1137
|
+
end
|
1138
|
+
|
990
1139
|
class Recorder
|
991
1140
|
attr_reader :log, :index
|
992
1141
|
attr_accessor :backup_frames
|
@@ -1001,8 +1150,8 @@ module DEBUGGER__
|
|
1001
1150
|
|
1002
1151
|
@tp_recorder ||= TracePoint.new(:line){|tp|
|
1003
1152
|
next unless Thread.current == thread
|
1004
|
-
|
1005
|
-
next if tp.path
|
1153
|
+
# can't be replaced by skip_location
|
1154
|
+
next if skip_internal_path?(tp.path)
|
1006
1155
|
loc = caller_locations(1, 1).first
|
1007
1156
|
next if skip_location?(loc)
|
1008
1157
|
|
data/lib/debug/tracer.rb
CHANGED
@@ -66,15 +66,7 @@ module DEBUGGER__
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def skip? tp
|
69
|
-
|
70
|
-
tp.path.start_with?('<internal:') ||
|
71
|
-
ThreadClient.current.management? ||
|
72
|
-
skip_path?(tp.path) ||
|
73
|
-
skip_with_pattern?(tp)
|
74
|
-
true
|
75
|
-
else
|
76
|
-
false
|
77
|
-
end
|
69
|
+
ThreadClient.current.management? || skip_path?(tp.path) || skip_with_pattern?(tp)
|
78
70
|
end
|
79
71
|
|
80
72
|
def skip_with_pattern?(tp)
|
@@ -82,18 +74,20 @@ module DEBUGGER__
|
|
82
74
|
end
|
83
75
|
|
84
76
|
def out tp, msg = nil, depth = caller.size - 1
|
85
|
-
location_str = colorize("#{tp.path}:#{tp.lineno}", [:GREEN])
|
77
|
+
location_str = colorize("#{FrameInfo.pretty_path(tp.path)}:#{tp.lineno}", [:GREEN])
|
86
78
|
buff = "#{header(depth)}#{msg} at #{location_str}"
|
87
79
|
|
88
80
|
if false # TODO: Ractor.main?
|
89
81
|
ThreadClient.current.on_trace self.object_id, buff
|
90
82
|
else
|
91
83
|
@output.puts buff
|
84
|
+
@output.flush
|
92
85
|
end
|
93
86
|
end
|
94
87
|
|
95
88
|
def puts msg
|
96
89
|
@output.puts msg
|
90
|
+
@output.flush
|
97
91
|
end
|
98
92
|
|
99
93
|
def minfo tp
|
@@ -125,7 +119,6 @@ module DEBUGGER__
|
|
125
119
|
next if skip?(tp)
|
126
120
|
|
127
121
|
depth = caller.size
|
128
|
-
sp = ' ' * depth
|
129
122
|
|
130
123
|
call_identifier_str =
|
131
124
|
if tp.defined_class
|
@@ -139,9 +132,11 @@ module DEBUGGER__
|
|
139
132
|
case tp.event
|
140
133
|
when :call, :c_call, :b_call
|
141
134
|
depth += 1 if tp.event == :c_call
|
135
|
+
sp = ' ' * depth
|
142
136
|
out tp, ">#{sp}#{call_identifier_str}", depth
|
143
137
|
when :return, :c_return, :b_return
|
144
138
|
depth += 1 if tp.event == :c_return
|
139
|
+
sp = ' ' * depth
|
145
140
|
return_str = colorize_magenta(DEBUGGER__.safe_inspect(tp.return_value, short: true))
|
146
141
|
out tp, "<#{sp}#{call_identifier_str} #=> #{return_str}", depth
|
147
142
|
end
|
@@ -191,7 +186,7 @@ module DEBUGGER__
|
|
191
186
|
@tracer = TracePoint.new(:a_call){|tp|
|
192
187
|
next if skip?(tp)
|
193
188
|
|
194
|
-
if tp.self
|
189
|
+
if M_OBJECT_ID.bind_call(tp.self) == @obj_id
|
195
190
|
klass = tp.defined_class
|
196
191
|
method = tp.method_id
|
197
192
|
method_info =
|
data/lib/debug/version.rb
CHANGED