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
data/lib/debug/session.rb
CHANGED
@@ -85,11 +85,13 @@ class RubyVM::InstructionSequence
|
|
85
85
|
end
|
86
86
|
|
87
87
|
module DEBUGGER__
|
88
|
-
|
88
|
+
PresetCommands = Struct.new(:commands, :source, :auto_continue)
|
89
|
+
SessionCommand = Struct.new(:block, :repeat, :unsafe, :cancel_auto_continue, :postmortem)
|
90
|
+
|
89
91
|
class PostmortemError < RuntimeError; end
|
90
92
|
|
91
93
|
class Session
|
92
|
-
attr_reader :intercepted_sigint_cmd, :process_group
|
94
|
+
attr_reader :intercepted_sigint_cmd, :process_group, :subsession_id
|
93
95
|
|
94
96
|
include Color
|
95
97
|
|
@@ -116,6 +118,7 @@ module DEBUGGER__
|
|
116
118
|
@intercepted_sigint_cmd = 'DEFAULT'
|
117
119
|
@process_group = ProcessGroup.new
|
118
120
|
@subsession_stack = []
|
121
|
+
@subsession_id = 0
|
119
122
|
|
120
123
|
@frame_map = {} # for DAP: {id => [threadId, frame_depth]} and CDP: {id => frame_depth}
|
121
124
|
@var_map = {1 => [:globals], } # {id => ...} for DAP
|
@@ -125,21 +128,41 @@ module DEBUGGER__
|
|
125
128
|
@obj_map = {} # { object_id => ... } for CDP
|
126
129
|
|
127
130
|
@tp_thread_begin = nil
|
131
|
+
@commands = {}
|
132
|
+
@unsafe_context = false
|
133
|
+
|
134
|
+
has_keep_script_lines = RubyVM.respond_to? :keep_script_lines
|
135
|
+
|
128
136
|
@tp_load_script = TracePoint.new(:script_compiled){|tp|
|
129
|
-
|
137
|
+
if !has_keep_script_lines || bps_pending_until_load?
|
138
|
+
eval_script = tp.eval_script unless has_keep_script_lines
|
139
|
+
ThreadClient.current.on_load tp.instruction_sequence, eval_script
|
140
|
+
end
|
130
141
|
}
|
131
142
|
@tp_load_script.enable
|
132
143
|
|
133
144
|
@thread_stopper = thread_stopper
|
134
145
|
self.postmortem = CONFIG[:postmortem]
|
146
|
+
|
147
|
+
register_default_command
|
135
148
|
end
|
136
149
|
|
137
150
|
def active?
|
138
151
|
!@q_evt.closed?
|
139
152
|
end
|
140
153
|
|
141
|
-
def
|
142
|
-
@
|
154
|
+
def remote?
|
155
|
+
@ui.remote?
|
156
|
+
end
|
157
|
+
|
158
|
+
def stop_stepping? file, line, subsession_id = nil
|
159
|
+
if @bps.has_key? [file, line]
|
160
|
+
true
|
161
|
+
elsif subsession_id && @subsession_id != subsession_id
|
162
|
+
true
|
163
|
+
else
|
164
|
+
false
|
165
|
+
end
|
143
166
|
end
|
144
167
|
|
145
168
|
def activate ui = nil, on_fork: false
|
@@ -193,6 +216,14 @@ module DEBUGGER__
|
|
193
216
|
def reset_ui ui
|
194
217
|
@ui.deactivate
|
195
218
|
@ui = ui
|
219
|
+
|
220
|
+
# activate new ui
|
221
|
+
@tp_thread_begin.disable
|
222
|
+
@ui.activate self
|
223
|
+
if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread)
|
224
|
+
thc.mark_as_management
|
225
|
+
end
|
226
|
+
@tp_thread_begin.enable
|
196
227
|
end
|
197
228
|
|
198
229
|
def pop_event
|
@@ -248,7 +279,7 @@ module DEBUGGER__
|
|
248
279
|
|
249
280
|
when :suspend
|
250
281
|
enter_subsession if ev_args.first != :replay
|
251
|
-
output.each{|str| @ui.puts str}
|
282
|
+
output.each{|str| @ui.puts str} unless @ui.ignore_output_on_suspend?
|
252
283
|
|
253
284
|
case ev_args.first
|
254
285
|
when :breakpoint
|
@@ -323,7 +354,7 @@ module DEBUGGER__
|
|
323
354
|
if @preset_command && !@preset_command.commands.empty?
|
324
355
|
@preset_command.commands += cs
|
325
356
|
else
|
326
|
-
@preset_command =
|
357
|
+
@preset_command = PresetCommands.new(cs, name, continue)
|
327
358
|
end
|
328
359
|
|
329
360
|
ThreadClient.current.on_init name if kick
|
@@ -396,97 +427,121 @@ module DEBUGGER__
|
|
396
427
|
end
|
397
428
|
end
|
398
429
|
|
399
|
-
def
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
else
|
404
|
-
return :retry
|
405
|
-
end
|
406
|
-
else
|
407
|
-
@repl_prev_line = line
|
408
|
-
end
|
409
|
-
|
410
|
-
/([^\s]+)(?:\s+(.+))?/ =~ line
|
411
|
-
cmd, arg = $1, $2
|
430
|
+
private def register_command *names,
|
431
|
+
repeat: false, unsafe: true, cancel_auto_continue: false, postmortem: true,
|
432
|
+
&b
|
433
|
+
cmd = SessionCommand.new(b, repeat, unsafe, cancel_auto_continue, postmortem)
|
412
434
|
|
413
|
-
|
435
|
+
names.each{|name|
|
436
|
+
@commands[name] = cmd
|
437
|
+
}
|
438
|
+
end
|
414
439
|
|
415
|
-
|
440
|
+
def register_default_command
|
416
441
|
### Control flow
|
417
442
|
|
418
443
|
# * `s[tep]`
|
419
444
|
# * Step in. Resume the program until next breakable point.
|
420
445
|
# * `s[tep] <n>`
|
421
446
|
# * Step in, resume the program at `<n>`th breakable point.
|
422
|
-
|
423
|
-
|
424
|
-
|
447
|
+
register_command 's', 'step',
|
448
|
+
repeat: true,
|
449
|
+
cancel_auto_continue: true,
|
450
|
+
postmortem: false do |arg|
|
425
451
|
step_command :in, arg
|
452
|
+
end
|
426
453
|
|
427
454
|
# * `n[ext]`
|
428
455
|
# * Step over. Resume the program until next line.
|
429
456
|
# * `n[ext] <n>`
|
430
457
|
# * Step over, same as `step <n>`.
|
431
|
-
|
432
|
-
|
433
|
-
|
458
|
+
register_command 'n', 'next',
|
459
|
+
repeat: true,
|
460
|
+
cancel_auto_continue: true,
|
461
|
+
postmortem: false do |arg|
|
434
462
|
step_command :next, arg
|
463
|
+
end
|
435
464
|
|
436
465
|
# * `fin[ish]`
|
437
466
|
# * Finish this frame. Resume the program until the current frame is finished.
|
438
467
|
# * `fin[ish] <n>`
|
439
468
|
# * Finish `<n>`th frames.
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
469
|
+
register_command 'fin', 'finish',
|
470
|
+
repeat: true,
|
471
|
+
cancel_auto_continue: true,
|
472
|
+
postmortem: false do |arg|
|
444
473
|
if arg&.to_i == 0
|
445
474
|
raise 'finish command with 0 does not make sense.'
|
446
475
|
end
|
447
476
|
|
448
477
|
step_command :finish, arg
|
478
|
+
end
|
449
479
|
|
450
|
-
# * `
|
480
|
+
# * `u[ntil]`
|
481
|
+
# * Similar to `next` command, but only stop later lines or the end of the current frame.
|
482
|
+
# * Similar to gdb's `advance` command.
|
483
|
+
# * `u[ntil] <[file:]line>
|
484
|
+
# * Run til the program reaches given location or the end of the current frame.
|
485
|
+
# * `u[ntil] <name>
|
486
|
+
# * Run til the program invokes a method `<name>`. `<name>` can be a regexp with `/name/`.
|
487
|
+
register_command 'u', 'until',
|
488
|
+
repeat: true,
|
489
|
+
cancel_auto_continue: true,
|
490
|
+
postmortem: false do |arg|
|
491
|
+
|
492
|
+
step_command :until, arg
|
493
|
+
end
|
494
|
+
|
495
|
+
# * `c` or `cont` or `continue`
|
451
496
|
# * Resume the program.
|
452
|
-
|
453
|
-
|
497
|
+
register_command 'c', 'cont', 'continue',
|
498
|
+
repeat: true,
|
499
|
+
cancel_auto_continue: true do |arg|
|
454
500
|
leave_subsession :continue
|
501
|
+
end
|
455
502
|
|
456
503
|
# * `q[uit]` or `Ctrl-D`
|
457
504
|
# * Finish debugger (with the debuggee process on non-remote debugging).
|
458
|
-
|
505
|
+
register_command 'q', 'quit' do |arg|
|
459
506
|
if ask 'Really quit?'
|
460
|
-
@ui.quit arg.to_i
|
507
|
+
@ui.quit arg.to_i do
|
508
|
+
request_tc :quit
|
509
|
+
end
|
461
510
|
leave_subsession :continue
|
462
511
|
else
|
463
|
-
|
512
|
+
next :retry
|
464
513
|
end
|
514
|
+
end
|
465
515
|
|
466
516
|
# * `q[uit]!`
|
467
517
|
# * Same as q[uit] but without the confirmation prompt.
|
468
|
-
|
469
|
-
@ui.quit arg.to_i
|
470
|
-
|
518
|
+
register_command 'q!', 'quit!', unsafe: false do |arg|
|
519
|
+
@ui.quit arg.to_i do
|
520
|
+
request_tc :quit
|
521
|
+
end
|
522
|
+
leave_subsession :continue
|
523
|
+
end
|
471
524
|
|
472
525
|
# * `kill`
|
473
526
|
# * Stop the debuggee process with `Kernel#exit!`.
|
474
|
-
|
527
|
+
register_command 'kill' do |arg|
|
475
528
|
if ask 'Really kill?'
|
476
529
|
exit! (arg || 1).to_i
|
477
530
|
else
|
478
|
-
|
531
|
+
next :retry
|
479
532
|
end
|
533
|
+
end
|
480
534
|
|
481
535
|
# * `kill!`
|
482
536
|
# * Same as kill but without the confirmation prompt.
|
483
|
-
|
537
|
+
register_command 'kill!', unsafe: false do |arg|
|
484
538
|
exit! (arg || 1).to_i
|
539
|
+
end
|
485
540
|
|
486
541
|
# * `sigint`
|
487
542
|
# * Execute SIGINT handler registered by the debuggee.
|
488
543
|
# * Note that this command should be used just after stop by `SIGINT`.
|
489
|
-
|
544
|
+
register_command 'sigint' do
|
490
545
|
begin
|
491
546
|
case cmd = @intercepted_sigint_cmd
|
492
547
|
when nil, 'IGNORE', :IGNORE, 'DEFAULT', :DEFAULT
|
@@ -502,8 +557,9 @@ module DEBUGGER__
|
|
502
557
|
rescue Exception => e
|
503
558
|
@ui.puts "Exception: #{e}"
|
504
559
|
@ui.puts e.backtrace.map{|line| " #{e}"}
|
505
|
-
|
560
|
+
next :retry
|
506
561
|
end
|
562
|
+
end
|
507
563
|
|
508
564
|
### Breakpoint
|
509
565
|
|
@@ -528,22 +584,21 @@ module DEBUGGER__
|
|
528
584
|
# * `b[reak] if: <expr>`
|
529
585
|
# * break if: `<expr>` is true at any lines.
|
530
586
|
# * Note that this feature is super slow.
|
531
|
-
|
532
|
-
check_postmortem
|
533
|
-
|
587
|
+
register_command 'b', 'break', postmortem: false, unsafe: false do |arg|
|
534
588
|
if arg == nil
|
535
589
|
show_bps
|
536
|
-
|
590
|
+
next :retry
|
537
591
|
else
|
538
592
|
case bp = repl_add_breakpoint(arg)
|
539
593
|
when :noretry
|
540
594
|
when nil
|
541
|
-
|
595
|
+
next :retry
|
542
596
|
else
|
543
597
|
show_bps bp
|
544
|
-
|
598
|
+
next :retry
|
545
599
|
end
|
546
600
|
end
|
601
|
+
end
|
547
602
|
|
548
603
|
# * `catch <Error>`
|
549
604
|
# * Set breakpoint on raising `<Error>`.
|
@@ -555,16 +610,16 @@ module DEBUGGER__
|
|
555
610
|
# * stops and run `<command>`, and continue.
|
556
611
|
# * `catch ... path: <path>`
|
557
612
|
# * stops if the exception is raised from a `<path>`. `<path>` can be a regexp with `/regexp/`.
|
558
|
-
|
559
|
-
check_postmortem
|
560
|
-
|
613
|
+
register_command 'catch', postmortem: false, unsafe: false do |arg|
|
561
614
|
if arg
|
562
615
|
bp = repl_add_catch_breakpoint arg
|
563
616
|
show_bps bp if bp
|
564
617
|
else
|
565
618
|
show_bps
|
566
619
|
end
|
567
|
-
|
620
|
+
|
621
|
+
:retry
|
622
|
+
end
|
568
623
|
|
569
624
|
# * `watch @ivar`
|
570
625
|
# * Stop the execution when the result of current scope's `@ivar` is changed.
|
@@ -577,24 +632,20 @@ module DEBUGGER__
|
|
577
632
|
# * stops and run `<command>`, and continue.
|
578
633
|
# * `watch ... path: <path>`
|
579
634
|
# * stops if the path matches `<path>`. `<path>` can be a regexp with `/regexp/`.
|
580
|
-
|
581
|
-
check_postmortem
|
582
|
-
|
635
|
+
register_command 'wat', 'watch', postmortem: false, unsafe: false do |arg|
|
583
636
|
if arg && arg.match?(/\A@\w+/)
|
584
637
|
repl_add_watch_breakpoint(arg)
|
585
638
|
else
|
586
639
|
show_bps
|
587
|
-
|
640
|
+
:retry
|
588
641
|
end
|
642
|
+
end
|
589
643
|
|
590
644
|
# * `del[ete]`
|
591
645
|
# * delete all breakpoints.
|
592
646
|
# * `del[ete] <bpnum>`
|
593
647
|
# * delete specified breakpoint.
|
594
|
-
|
595
|
-
check_postmortem
|
596
|
-
|
597
|
-
bp =
|
648
|
+
register_command 'del', 'delete', postmortem: false, unsafe: false do |arg|
|
598
649
|
case arg
|
599
650
|
when nil
|
600
651
|
show_bps
|
@@ -602,12 +653,13 @@ module DEBUGGER__
|
|
602
653
|
delete_bp
|
603
654
|
end
|
604
655
|
when /\d+/
|
605
|
-
delete_bp arg.to_i
|
656
|
+
bp = delete_bp arg.to_i
|
606
657
|
else
|
607
658
|
nil
|
608
659
|
end
|
609
660
|
@ui.puts "deleted: \##{bp[0]} #{bp[1]}" if bp
|
610
|
-
|
661
|
+
:retry
|
662
|
+
end
|
611
663
|
|
612
664
|
### Information
|
613
665
|
|
@@ -619,7 +671,7 @@ module DEBUGGER__
|
|
619
671
|
# * Only shows frames with method name or location info that matches `/regexp/`.
|
620
672
|
# * `bt <num> /regexp/` or `backtrace <num> /regexp/`
|
621
673
|
# * Only shows first `<num>` frames with method name or location info that matches `/regexp/`.
|
622
|
-
|
674
|
+
register_command 'bt', 'backtrace', unsafe: false do |arg|
|
623
675
|
case arg
|
624
676
|
when /\A(\d+)\z/
|
625
677
|
request_tc [:show, :backtrace, arg.to_i, nil]
|
@@ -632,6 +684,7 @@ module DEBUGGER__
|
|
632
684
|
else
|
633
685
|
request_tc [:show, :backtrace, nil, nil]
|
634
686
|
end
|
687
|
+
end
|
635
688
|
|
636
689
|
# * `l[ist]`
|
637
690
|
# * Show current frame's source code.
|
@@ -640,7 +693,7 @@ module DEBUGGER__
|
|
640
693
|
# * Show predecessor lines as opposed to the `list` command.
|
641
694
|
# * `l[ist] <start>` or `l[ist] <start>-<end>`
|
642
695
|
# * Show current frame's source code from the line <start> to <end> if given.
|
643
|
-
|
696
|
+
register_command 'l', 'list', repeat: true, unsafe: false do |arg|
|
644
697
|
case arg ? arg.strip : nil
|
645
698
|
when /\A(\d+)\z/
|
646
699
|
request_tc [:show, :list, {start_line: arg.to_i - 1}]
|
@@ -652,45 +705,63 @@ module DEBUGGER__
|
|
652
705
|
request_tc [:show, :list]
|
653
706
|
else
|
654
707
|
@ui.puts "Can not handle list argument: #{arg}"
|
655
|
-
|
708
|
+
:retry
|
656
709
|
end
|
710
|
+
end
|
711
|
+
|
712
|
+
# * `whereami`
|
713
|
+
# * Show the current frame with source code.
|
714
|
+
register_command 'whereami', unsafe: false do
|
715
|
+
request_tc [:show, :whereami]
|
716
|
+
end
|
657
717
|
|
658
718
|
# * `edit`
|
659
719
|
# * Open the current file on the editor (use `EDITOR` environment variable).
|
660
720
|
# * Note that edited file will not be reloaded.
|
661
721
|
# * `edit <file>`
|
662
722
|
# * Open <file> on the editor.
|
663
|
-
|
723
|
+
register_command 'edit' do |arg|
|
664
724
|
if @ui.remote?
|
665
725
|
@ui.puts "not supported on the remote console."
|
666
|
-
|
726
|
+
next :retry
|
667
727
|
end
|
668
728
|
|
669
729
|
begin
|
670
730
|
arg = resolve_path(arg) if arg
|
671
731
|
rescue Errno::ENOENT
|
672
732
|
@ui.puts "not found: #{arg}"
|
673
|
-
|
733
|
+
next :retry
|
674
734
|
end
|
675
735
|
|
676
736
|
request_tc [:show, :edit, arg]
|
737
|
+
end
|
738
|
+
|
739
|
+
info_subcommands = nil
|
740
|
+
info_subcommands_abbrev = nil
|
677
741
|
|
678
742
|
# * `i[nfo]`
|
679
|
-
#
|
680
|
-
# * `i[nfo]
|
743
|
+
# * Show information about current frame (local/instance variables and defined constants).
|
744
|
+
# * `i[nfo]` <subcommand>
|
745
|
+
# * `info` has the following sub-commands.
|
746
|
+
# * Sub-commands can be specified with few letters which is unambiguous, like `l` for 'locals'.
|
747
|
+
# * `i[nfo] l or locals or local_variables`
|
681
748
|
# * Show information about the current frame (local variables)
|
682
|
-
# * It includes `self` as `%self` and a return value as
|
683
|
-
# * `i[nfo] i
|
749
|
+
# * It includes `self` as `%self` and a return value as `_return`.
|
750
|
+
# * `i[nfo] i or ivars or instance_variables`
|
684
751
|
# * Show information about instance variables about `self`.
|
685
|
-
#
|
752
|
+
# * `info ivars <expr>` shows the instance variables of the result of `<expr>`.
|
753
|
+
# * `i[nfo] c or consts or constants`
|
686
754
|
# * Show information about accessible constants except toplevel constants.
|
687
|
-
#
|
755
|
+
# * `info consts <expr>` shows the constants of a class/module of the result of `<expr>`
|
756
|
+
# * `i[nfo] g or globals or global_variables`
|
688
757
|
# * Show information about global variables
|
758
|
+
# * `i[nfo] th or threads`
|
759
|
+
# * Show all threads (same as `th[read]`).
|
760
|
+
# * `i[nfo] b or breakpoints or w or watchpoints`
|
761
|
+
# * Show all breakpoints and watchpoints.
|
689
762
|
# * `i[nfo] ... /regexp/`
|
690
763
|
# * Filter the output with `/regexp/`.
|
691
|
-
|
692
|
-
# * Show all threads (same as `th[read]`).
|
693
|
-
when 'i', 'info'
|
764
|
+
register_command 'i', 'info', unsafe: false do |arg|
|
694
765
|
if /\/(.+)\/\z/ =~ arg
|
695
766
|
pat = Regexp.compile($1)
|
696
767
|
sub = $~.pre_match.strip
|
@@ -698,51 +769,85 @@ module DEBUGGER__
|
|
698
769
|
sub = arg
|
699
770
|
end
|
700
771
|
|
772
|
+
if /\A(.+?)\b(.+)/ =~ sub
|
773
|
+
sub = $1
|
774
|
+
opt = $2.strip
|
775
|
+
opt = nil if opt.empty?
|
776
|
+
end
|
777
|
+
|
778
|
+
if sub && !info_subcommands
|
779
|
+
info_subcommands = {
|
780
|
+
locals: %w[ locals local_variables ],
|
781
|
+
ivars: %w[ ivars instance_variables ],
|
782
|
+
consts: %w[ consts constants ],
|
783
|
+
globals:%w[ globals global_variables ],
|
784
|
+
threads:%w[ threads ],
|
785
|
+
breaks: %w[ breakpoints ],
|
786
|
+
watchs: %w[ watchpoints ],
|
787
|
+
}
|
788
|
+
|
789
|
+
require_relative 'abbrev_command'
|
790
|
+
info_subcommands_abbrev = AbbrevCommand.new(info_subcommands)
|
791
|
+
end
|
792
|
+
|
793
|
+
if sub
|
794
|
+
sub = info_subcommands_abbrev.search sub, :unknown do |candidates|
|
795
|
+
# note: unreached now
|
796
|
+
@ui.puts "Ambiguous command '#{sub}': #{candidates.join(' ')}"
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
701
800
|
case sub
|
702
801
|
when nil
|
703
802
|
request_tc [:show, :default, pat] # something useful
|
704
|
-
when
|
803
|
+
when :locals
|
705
804
|
request_tc [:show, :locals, pat]
|
706
|
-
when
|
707
|
-
request_tc [:show, :ivars, pat]
|
708
|
-
when
|
709
|
-
request_tc [:show, :consts, pat]
|
710
|
-
when
|
805
|
+
when :ivars
|
806
|
+
request_tc [:show, :ivars, pat, opt]
|
807
|
+
when :consts
|
808
|
+
request_tc [:show, :consts, pat, opt]
|
809
|
+
when :globals
|
711
810
|
request_tc [:show, :globals, pat]
|
712
|
-
when
|
811
|
+
when :threads
|
713
812
|
thread_list
|
714
|
-
|
813
|
+
:retry
|
814
|
+
when :breaks, :watchs
|
815
|
+
show_bps
|
816
|
+
:retry
|
715
817
|
else
|
716
818
|
@ui.puts "unrecognized argument for info command: #{arg}"
|
717
819
|
show_help 'info'
|
718
|
-
|
820
|
+
:retry
|
719
821
|
end
|
822
|
+
end
|
720
823
|
|
721
824
|
# * `o[utline]` or `ls`
|
722
825
|
# * Show you available methods, constants, local variables, and instance variables in the current scope.
|
723
826
|
# * `o[utline] <expr>` or `ls <expr>`
|
724
827
|
# * Show you available methods and instance variables of the given object.
|
725
828
|
# * If the object is a class/module, it also lists its constants.
|
726
|
-
|
829
|
+
register_command 'outline', 'o', 'ls', unsafe: false do |arg|
|
727
830
|
request_tc [:show, :outline, arg]
|
831
|
+
end
|
728
832
|
|
729
833
|
# * `display`
|
730
834
|
# * Show display setting.
|
731
835
|
# * `display <expr>`
|
732
836
|
# * Show the result of `<expr>` at every suspended timing.
|
733
|
-
|
837
|
+
register_command 'display', postmortem: false do |arg|
|
734
838
|
if arg && !arg.empty?
|
735
839
|
@displays << arg
|
736
840
|
request_tc [:eval, :try_display, @displays]
|
737
841
|
else
|
738
842
|
request_tc [:eval, :display, @displays]
|
739
843
|
end
|
844
|
+
end
|
740
845
|
|
741
846
|
# * `undisplay`
|
742
847
|
# * Remove all display settings.
|
743
848
|
# * `undisplay <displaynum>`
|
744
849
|
# * Remove a specified display setting.
|
745
|
-
|
850
|
+
register_command 'undisplay', postmortem: false, unsafe: false do |arg|
|
746
851
|
case arg
|
747
852
|
when /(\d+)/
|
748
853
|
if @displays[n = $1.to_i]
|
@@ -753,8 +858,9 @@ module DEBUGGER__
|
|
753
858
|
if ask "clear all?", 'N'
|
754
859
|
@displays.clear
|
755
860
|
end
|
756
|
-
|
861
|
+
:retry
|
757
862
|
end
|
863
|
+
end
|
758
864
|
|
759
865
|
### Frame control
|
760
866
|
|
@@ -762,53 +868,57 @@ module DEBUGGER__
|
|
762
868
|
# * Show the current frame.
|
763
869
|
# * `f[rame] <framenum>`
|
764
870
|
# * Specify a current frame. Evaluation are run on specified frame.
|
765
|
-
|
871
|
+
register_command 'frame', 'f', unsafe: false do |arg|
|
766
872
|
request_tc [:frame, :set, arg]
|
873
|
+
end
|
767
874
|
|
768
875
|
# * `up`
|
769
876
|
# * Specify the upper frame.
|
770
|
-
|
877
|
+
register_command 'up', repeat: true, unsafe: false do |arg|
|
771
878
|
request_tc [:frame, :up]
|
879
|
+
end
|
772
880
|
|
773
881
|
# * `down`
|
774
882
|
# * Specify the lower frame.
|
775
|
-
|
883
|
+
register_command 'down', repeat: true, unsafe: false do |arg|
|
776
884
|
request_tc [:frame, :down]
|
885
|
+
end
|
777
886
|
|
778
887
|
### Evaluate
|
779
888
|
|
780
889
|
# * `p <expr>`
|
781
890
|
# * Evaluate like `p <expr>` on the current frame.
|
782
|
-
|
891
|
+
register_command 'p' do |arg|
|
783
892
|
request_tc [:eval, :p, arg.to_s]
|
893
|
+
end
|
784
894
|
|
785
895
|
# * `pp <expr>`
|
786
896
|
# * Evaluate like `pp <expr>` on the current frame.
|
787
|
-
|
897
|
+
register_command 'pp' do |arg|
|
788
898
|
request_tc [:eval, :pp, arg.to_s]
|
899
|
+
end
|
789
900
|
|
790
901
|
# * `eval <expr>`
|
791
902
|
# * Evaluate `<expr>` on the current frame.
|
792
|
-
|
903
|
+
register_command 'eval', 'call' do |arg|
|
793
904
|
if arg == nil || arg.empty?
|
794
905
|
show_help 'eval'
|
795
906
|
@ui.puts "\nTo evaluate the variable `#{cmd}`, use `pp #{cmd}` instead."
|
796
|
-
|
907
|
+
:retry
|
797
908
|
else
|
798
909
|
request_tc [:eval, :call, arg]
|
799
910
|
end
|
911
|
+
end
|
800
912
|
|
801
913
|
# * `irb`
|
802
914
|
# * Invoke `irb` on the current frame.
|
803
|
-
|
915
|
+
register_command 'irb' do |arg|
|
804
916
|
if @ui.remote?
|
805
917
|
@ui.puts "not supported on the remote console."
|
806
|
-
|
918
|
+
:retry
|
807
919
|
end
|
808
920
|
request_tc [:eval, :irb]
|
809
|
-
|
810
|
-
# don't repeat irb command
|
811
|
-
@repl_prev_line = nil
|
921
|
+
end
|
812
922
|
|
813
923
|
### Trace
|
814
924
|
# * `trace`
|
@@ -829,7 +939,7 @@ module DEBUGGER__
|
|
829
939
|
# * Disable tracer specified by `<num>` (use `trace` command to check the numbers).
|
830
940
|
# * `trace off [line|call|pass]`
|
831
941
|
# * Disable all tracers. If `<type>` is provided, disable specified type tracers.
|
832
|
-
|
942
|
+
register_command 'trace', postmortem: false, unsafe: false do |arg|
|
833
943
|
if (re = /\s+into:\s*(.+)/) =~ arg
|
834
944
|
into = $1
|
835
945
|
arg.sub!(re, '')
|
@@ -847,19 +957,19 @@ module DEBUGGER__
|
|
847
957
|
@ui.puts "* \##{i} #{t}"
|
848
958
|
}
|
849
959
|
@ui.puts
|
850
|
-
|
960
|
+
:retry
|
851
961
|
|
852
962
|
when /\Aline\z/
|
853
963
|
add_tracer LineTracer.new(@ui, pattern: pattern, into: into)
|
854
|
-
|
964
|
+
:retry
|
855
965
|
|
856
966
|
when /\Acall\z/
|
857
967
|
add_tracer CallTracer.new(@ui, pattern: pattern, into: into)
|
858
|
-
|
968
|
+
:retry
|
859
969
|
|
860
970
|
when /\Aexception\z/
|
861
971
|
add_tracer ExceptionTracer.new(@ui, pattern: pattern, into: into)
|
862
|
-
|
972
|
+
:retry
|
863
973
|
|
864
974
|
when /\Aobject\s+(.+)/
|
865
975
|
request_tc [:trace, :object, $1.strip, {pattern: pattern, into: into}]
|
@@ -871,7 +981,7 @@ module DEBUGGER__
|
|
871
981
|
else
|
872
982
|
@ui.puts "Unmatched: #{$1}"
|
873
983
|
end
|
874
|
-
|
984
|
+
:retry
|
875
985
|
|
876
986
|
when /\Aoff(\s+(line|call|exception|object))?\z/
|
877
987
|
@tracers.values.each{|t|
|
@@ -880,12 +990,13 @@ module DEBUGGER__
|
|
880
990
|
@ui.puts "Disable #{t.to_s}"
|
881
991
|
end
|
882
992
|
}
|
883
|
-
|
993
|
+
:retry
|
884
994
|
|
885
995
|
else
|
886
996
|
@ui.puts "Unknown trace option: #{arg.inspect}"
|
887
|
-
|
997
|
+
:retry
|
888
998
|
end
|
999
|
+
end
|
889
1000
|
|
890
1001
|
# Record
|
891
1002
|
# * `record`
|
@@ -897,14 +1008,15 @@ module DEBUGGER__
|
|
897
1008
|
# * `s[tep]` does stepping forward with the last log.
|
898
1009
|
# * `step reset`
|
899
1010
|
# * Stop replay .
|
900
|
-
|
1011
|
+
register_command 'record', postmortem: false, unsafe: false do |arg|
|
901
1012
|
case arg
|
902
1013
|
when nil, 'on', 'off'
|
903
1014
|
request_tc [:record, arg&.to_sym]
|
904
1015
|
else
|
905
1016
|
@ui.puts "unknown command: #{arg}"
|
906
|
-
|
1017
|
+
:retry
|
907
1018
|
end
|
1019
|
+
end
|
908
1020
|
|
909
1021
|
### Thread control
|
910
1022
|
|
@@ -912,7 +1024,7 @@ module DEBUGGER__
|
|
912
1024
|
# * Show all threads.
|
913
1025
|
# * `th[read] <thnum>`
|
914
1026
|
# * Switch thread specified by `<thnum>`.
|
915
|
-
|
1027
|
+
register_command 'th', 'thread', unsafe: false do |arg|
|
916
1028
|
case arg
|
917
1029
|
when nil, 'list', 'l'
|
918
1030
|
thread_list
|
@@ -921,7 +1033,8 @@ module DEBUGGER__
|
|
921
1033
|
else
|
922
1034
|
@ui.puts "unknown thread command: #{arg}"
|
923
1035
|
end
|
924
|
-
|
1036
|
+
:retry
|
1037
|
+
end
|
925
1038
|
|
926
1039
|
### Configuration
|
927
1040
|
# * `config`
|
@@ -934,13 +1047,14 @@ module DEBUGGER__
|
|
934
1047
|
# * Append `<val>` to `<name>` if it is an array.
|
935
1048
|
# * `config unset <name>`
|
936
1049
|
# * Set <name> to default.
|
937
|
-
|
1050
|
+
register_command 'config', unsafe: false do |arg|
|
938
1051
|
config_command arg
|
939
|
-
|
1052
|
+
:retry
|
1053
|
+
end
|
940
1054
|
|
941
1055
|
# * `source <file>`
|
942
1056
|
# * Evaluate lines in `<file>` as debug commands.
|
943
|
-
|
1057
|
+
register_command 'source' do |arg|
|
944
1058
|
if arg
|
945
1059
|
begin
|
946
1060
|
cmds = File.readlines(path = File.expand_path(arg))
|
@@ -951,7 +1065,8 @@ module DEBUGGER__
|
|
951
1065
|
else
|
952
1066
|
show_help 'source'
|
953
1067
|
end
|
954
|
-
|
1068
|
+
:retry
|
1069
|
+
end
|
955
1070
|
|
956
1071
|
# * `open`
|
957
1072
|
# * open debuggee port on UNIX domain socket and wait for attaching.
|
@@ -962,26 +1077,28 @@ module DEBUGGER__
|
|
962
1077
|
# * open debuggee port for VSCode and launch VSCode if available.
|
963
1078
|
# * `open chrome`
|
964
1079
|
# * open debuggee port for Chrome and wait for attaching.
|
965
|
-
|
1080
|
+
register_command 'open' do |arg|
|
966
1081
|
case arg&.downcase
|
967
1082
|
when '', nil
|
968
|
-
|
969
|
-
when 'vscode'
|
970
|
-
repl_open_vscode
|
971
|
-
when /\A(.+):(\d+)\z/
|
972
|
-
repl_open_tcp $1, $2.to_i
|
1083
|
+
::DEBUGGER__.open nonstop: true
|
973
1084
|
when /\A(\d+)z/
|
974
|
-
|
1085
|
+
::DEBUGGER__.open_tcp host: nil, port: $1.to_i, nonstop: true
|
1086
|
+
when /\A(.+):(\d+)\z/
|
1087
|
+
::DEBUGGER__.open_tcp host: $1, port: $2.to_i, nonstop: true
|
975
1088
|
when 'tcp'
|
976
|
-
|
1089
|
+
::DEBUGGER__.open_tcp host: CONFIG[:host], port: (CONFIG[:port] || 0), nonstop: true
|
1090
|
+
when 'vscode'
|
1091
|
+
CONFIG[:open] = 'vscode'
|
1092
|
+
::DEBUGGER__.open nonstop: true
|
977
1093
|
when 'chrome', 'cdp'
|
978
|
-
CONFIG[:
|
979
|
-
|
1094
|
+
CONFIG[:open] = 'chrome'
|
1095
|
+
::DEBUGGER__.open_tcp host: CONFIG[:host], port: (CONFIG[:port] || 0), nonstop: true
|
980
1096
|
else
|
981
1097
|
raise "Unknown arg: #{arg}"
|
982
1098
|
end
|
983
1099
|
|
984
|
-
|
1100
|
+
:retry
|
1101
|
+
end
|
985
1102
|
|
986
1103
|
### Help
|
987
1104
|
|
@@ -989,26 +1106,38 @@ module DEBUGGER__
|
|
989
1106
|
# * Show help for all commands.
|
990
1107
|
# * `h[elp] <command>`
|
991
1108
|
# * Show help for the given command.
|
992
|
-
|
1109
|
+
register_command 'h', 'help', '?', unsafe: false do |arg|
|
993
1110
|
show_help arg
|
994
|
-
|
1111
|
+
:retry
|
1112
|
+
end
|
1113
|
+
end
|
995
1114
|
|
996
|
-
|
1115
|
+
def process_command line
|
1116
|
+
if line.empty?
|
1117
|
+
if @repl_prev_line
|
1118
|
+
line = @repl_prev_line
|
1119
|
+
else
|
1120
|
+
return :retry
|
1121
|
+
end
|
1122
|
+
else
|
1123
|
+
@repl_prev_line = line
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
/([^\s]+)(?:\s+(.+))?/ =~ line
|
1127
|
+
cmd_name, cmd_arg = $1, $2
|
1128
|
+
|
1129
|
+
if cmd = @commands[cmd_name]
|
1130
|
+
check_postmortem if !cmd.postmortem
|
1131
|
+
check_unsafe if cmd.unsafe
|
1132
|
+
cancel_auto_continue if cmd.cancel_auto_continue
|
1133
|
+
@repl_prev_line = nil if !cmd.repeat
|
1134
|
+
|
1135
|
+
cmd.block.call(cmd_arg)
|
997
1136
|
else
|
998
|
-
request_tc [:eval, :pp, line]
|
999
|
-
=begin
|
1000
1137
|
@repl_prev_line = nil
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
spell_checker = DidYouMean::SpellChecker.new(dictionary: DEBUGGER__.commands)
|
1005
|
-
correction = spell_checker.correct(line.split(/\s/).first || '')
|
1006
|
-
@ui.puts "Did you mean? #{correction.join(' or ')}" unless correction.empty?
|
1007
|
-
rescue LoadError
|
1008
|
-
# Don't use D
|
1009
|
-
end
|
1010
|
-
return :retry
|
1011
|
-
=end
|
1138
|
+
check_unsafe
|
1139
|
+
|
1140
|
+
request_tc [:eval, :pp, line]
|
1012
1141
|
end
|
1013
1142
|
|
1014
1143
|
rescue Interrupt
|
@@ -1024,31 +1153,12 @@ module DEBUGGER__
|
|
1024
1153
|
return :retry
|
1025
1154
|
end
|
1026
1155
|
|
1027
|
-
def
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
thc.mark_as_management
|
1156
|
+
def step_command type, arg
|
1157
|
+
if type == :until
|
1158
|
+
leave_subsession [:step, type, arg]
|
1159
|
+
return
|
1032
1160
|
end
|
1033
|
-
@tp_thread_begin.enable
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
def repl_open_tcp host, port, **kw
|
1037
|
-
DEBUGGER__.open_tcp host: host, port: port, nonstop: true, **kw
|
1038
|
-
repl_open_setup
|
1039
|
-
end
|
1040
1161
|
|
1041
|
-
def repl_open
|
1042
|
-
DEBUGGER__.open nonstop: true
|
1043
|
-
repl_open_setup
|
1044
|
-
end
|
1045
|
-
|
1046
|
-
def repl_open_vscode
|
1047
|
-
CONFIG[:open_frontend] = 'vscode'
|
1048
|
-
repl_open
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
def step_command type, arg
|
1052
1162
|
case arg
|
1053
1163
|
when nil, /\A\d+\z/
|
1054
1164
|
if type == :in && @tc.recorder&.replaying?
|
@@ -1056,12 +1166,14 @@ module DEBUGGER__
|
|
1056
1166
|
else
|
1057
1167
|
leave_subsession [:step, type, arg&.to_i]
|
1058
1168
|
end
|
1059
|
-
when /\
|
1169
|
+
when /\A(back)\z/, /\A(back)\s+(\d+)\z/, /\A(reset)\z/
|
1060
1170
|
if type != :in
|
1061
1171
|
@ui.puts "only `step #{arg}` is supported."
|
1062
1172
|
:retry
|
1063
1173
|
else
|
1064
|
-
|
1174
|
+
type = $1.to_sym
|
1175
|
+
iter = $2&.to_i
|
1176
|
+
request_tc [:step, type, iter]
|
1065
1177
|
end
|
1066
1178
|
else
|
1067
1179
|
@ui.puts "Unknown option: #{arg}"
|
@@ -1209,6 +1321,10 @@ module DEBUGGER__
|
|
1209
1321
|
|
1210
1322
|
# breakpoint management
|
1211
1323
|
|
1324
|
+
def bps_pending_until_load?
|
1325
|
+
@bps.any?{|key, bp| bp.pending_until_load?}
|
1326
|
+
end
|
1327
|
+
|
1212
1328
|
def iterate_bps
|
1213
1329
|
deleted_bps = []
|
1214
1330
|
i = 0
|
@@ -1255,8 +1371,6 @@ module DEBUGGER__
|
|
1255
1371
|
|
1256
1372
|
def add_bp bp
|
1257
1373
|
# don't repeat commands that add breakpoints
|
1258
|
-
@repl_prev_line = nil
|
1259
|
-
|
1260
1374
|
if @bps.has_key? bp.key
|
1261
1375
|
if bp.duplicable?
|
1262
1376
|
bp
|
@@ -1288,7 +1402,7 @@ module DEBUGGER__
|
|
1288
1402
|
|
1289
1403
|
BREAK_KEYWORDS = %w(if: do: pre: path:).freeze
|
1290
1404
|
|
1291
|
-
def parse_break arg
|
1405
|
+
private def parse_break type, arg
|
1292
1406
|
mode = :sig
|
1293
1407
|
expr = Hash.new{|h, k| h[k] = []}
|
1294
1408
|
arg.split(' ').each{|w|
|
@@ -1305,13 +1419,18 @@ module DEBUGGER__
|
|
1305
1419
|
expr[:path] = Regexp.compile($1)
|
1306
1420
|
end
|
1307
1421
|
|
1422
|
+
if expr[:do] || expr[:pre]
|
1423
|
+
check_unsafe
|
1424
|
+
expr[:cmd] = [type, expr[:pre], expr[:do]]
|
1425
|
+
end
|
1426
|
+
|
1308
1427
|
expr
|
1309
1428
|
end
|
1310
1429
|
|
1311
1430
|
def repl_add_breakpoint arg
|
1312
|
-
expr = parse_break arg.strip
|
1431
|
+
expr = parse_break 'break', arg.strip
|
1313
1432
|
cond = expr[:if]
|
1314
|
-
cmd
|
1433
|
+
cmd = expr[:cmd]
|
1315
1434
|
path = expr[:path]
|
1316
1435
|
|
1317
1436
|
case expr[:sig]
|
@@ -1332,9 +1451,9 @@ module DEBUGGER__
|
|
1332
1451
|
end
|
1333
1452
|
|
1334
1453
|
def repl_add_catch_breakpoint arg
|
1335
|
-
expr = parse_break arg.strip
|
1454
|
+
expr = parse_break 'catch', arg.strip
|
1336
1455
|
cond = expr[:if]
|
1337
|
-
cmd
|
1456
|
+
cmd = expr[:cmd]
|
1338
1457
|
path = expr[:path]
|
1339
1458
|
|
1340
1459
|
bp = CatchBreakpoint.new(expr[:sig], cond: cond, command: cmd, path: path)
|
@@ -1342,9 +1461,9 @@ module DEBUGGER__
|
|
1342
1461
|
end
|
1343
1462
|
|
1344
1463
|
def repl_add_watch_breakpoint arg
|
1345
|
-
expr = parse_break arg.strip
|
1464
|
+
expr = parse_break 'watch', arg.strip
|
1346
1465
|
cond = expr[:if]
|
1347
|
-
cmd
|
1466
|
+
cmd = expr[:cmd]
|
1348
1467
|
path = Regexp.compile(expr[:path]) if expr[:path]
|
1349
1468
|
|
1350
1469
|
request_tc [:breakpoint, :watch, expr[:sig], cond, cmd, path]
|
@@ -1405,8 +1524,6 @@ module DEBUGGER__
|
|
1405
1524
|
# tracers
|
1406
1525
|
|
1407
1526
|
def add_tracer tracer
|
1408
|
-
# don't repeat commands that add tracers
|
1409
|
-
@repl_prev_line = nil
|
1410
1527
|
if @tracers.has_key? tracer.key
|
1411
1528
|
tracer.disable
|
1412
1529
|
@ui.puts "Duplicated tracer: #{tracer}"
|
@@ -1564,10 +1681,11 @@ module DEBUGGER__
|
|
1564
1681
|
end
|
1565
1682
|
|
1566
1683
|
private def enter_subsession
|
1684
|
+
@subsession_id += 1
|
1567
1685
|
if !@subsession_stack.empty?
|
1568
|
-
DEBUGGER__.
|
1686
|
+
DEBUGGER__.debug{ "Enter subsession (nested #{@subsession_stack.size})" }
|
1569
1687
|
else
|
1570
|
-
DEBUGGER__.
|
1688
|
+
DEBUGGER__.debug{ "Enter subsession" }
|
1571
1689
|
stop_all_threads
|
1572
1690
|
@process_group.lock
|
1573
1691
|
end
|
@@ -1580,11 +1698,11 @@ module DEBUGGER__
|
|
1580
1698
|
@subsession_stack.pop
|
1581
1699
|
|
1582
1700
|
if @subsession_stack.empty?
|
1583
|
-
DEBUGGER__.
|
1701
|
+
DEBUGGER__.debug{ "Leave subsession" }
|
1584
1702
|
@process_group.unlock
|
1585
1703
|
restart_all_threads
|
1586
1704
|
else
|
1587
|
-
DEBUGGER__.
|
1705
|
+
DEBUGGER__.debug{ "Leave subsession (nested #{@subsession_stack.size})" }
|
1588
1706
|
end
|
1589
1707
|
|
1590
1708
|
request_tc type if type
|
@@ -1723,6 +1841,12 @@ module DEBUGGER__
|
|
1723
1841
|
end
|
1724
1842
|
end
|
1725
1843
|
|
1844
|
+
def check_unsafe
|
1845
|
+
if @unsafe_context
|
1846
|
+
raise RuntimeError, "#{@repl_prev_line.dump} is not allowed on unsafe context."
|
1847
|
+
end
|
1848
|
+
end
|
1849
|
+
|
1726
1850
|
def enter_postmortem_session exc
|
1727
1851
|
return unless exc.instance_variable_defined? :@__debugger_postmortem_frames
|
1728
1852
|
|
@@ -1802,6 +1926,17 @@ module DEBUGGER__
|
|
1802
1926
|
end
|
1803
1927
|
end
|
1804
1928
|
|
1929
|
+
def set_no_sigint_hook old, new
|
1930
|
+
return unless old != new
|
1931
|
+
return unless @ui.respond_to? :activate_sigint
|
1932
|
+
|
1933
|
+
if old # no -> yes
|
1934
|
+
@ui.activate_sigint
|
1935
|
+
else
|
1936
|
+
@ui.deactivate_sigint
|
1937
|
+
end
|
1938
|
+
end
|
1939
|
+
|
1805
1940
|
def save_int_trap cmd
|
1806
1941
|
prev, @intercepted_sigint_cmd = @intercepted_sigint_cmd, cmd
|
1807
1942
|
prev
|
@@ -1906,7 +2041,7 @@ module DEBUGGER__
|
|
1906
2041
|
end
|
1907
2042
|
|
1908
2043
|
def locked?
|
1909
|
-
# DEBUGGER__.
|
2044
|
+
# DEBUGGER__.debug{ "locked? #{@lock_level}" }
|
1910
2045
|
@lock_level > 0
|
1911
2046
|
end
|
1912
2047
|
|
@@ -1991,6 +2126,10 @@ module DEBUGGER__
|
|
1991
2126
|
end
|
1992
2127
|
end
|
1993
2128
|
|
2129
|
+
def ignore_output_on_suspend?
|
2130
|
+
false
|
2131
|
+
end
|
2132
|
+
|
1994
2133
|
def flush
|
1995
2134
|
end
|
1996
2135
|
end
|
@@ -2027,19 +2166,22 @@ module DEBUGGER__
|
|
2027
2166
|
def self.start nonstop: false, **kw
|
2028
2167
|
CONFIG.set_config(**kw)
|
2029
2168
|
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2169
|
+
if CONFIG[:open]
|
2170
|
+
open nonstop: nonstop, **kw
|
2171
|
+
else
|
2172
|
+
unless defined? SESSION
|
2173
|
+
require_relative 'local'
|
2174
|
+
initialize_session{ UI_LocalConsole.new }
|
2175
|
+
end
|
2176
|
+
setup_initial_suspend unless nonstop
|
2033
2177
|
end
|
2034
|
-
|
2035
|
-
setup_initial_suspend unless nonstop
|
2036
2178
|
end
|
2037
2179
|
|
2038
2180
|
def self.open host: nil, port: CONFIG[:port], sock_path: nil, sock_dir: nil, nonstop: false, **kw
|
2039
2181
|
CONFIG.set_config(**kw)
|
2040
2182
|
require_relative 'server'
|
2041
2183
|
|
2042
|
-
if port || CONFIG[:
|
2184
|
+
if port || CONFIG[:open] == 'chrome' || (!::Addrinfo.respond_to?(:unix))
|
2043
2185
|
open_tcp host: host, port: (port || 0), nonstop: nonstop
|
2044
2186
|
else
|
2045
2187
|
open_unix sock_path: sock_path, sock_dir: sock_dir, nonstop: nonstop
|
@@ -2101,6 +2243,18 @@ module DEBUGGER__
|
|
2101
2243
|
end
|
2102
2244
|
end
|
2103
2245
|
|
2246
|
+
# Exiting control
|
2247
|
+
|
2248
|
+
class << self
|
2249
|
+
def skip_all
|
2250
|
+
@skip_all = true
|
2251
|
+
end
|
2252
|
+
|
2253
|
+
def skip?
|
2254
|
+
@skip_all
|
2255
|
+
end
|
2256
|
+
end
|
2257
|
+
|
2104
2258
|
def self.load_rc
|
2105
2259
|
[[File.expand_path('~/.rdbgrc'), true],
|
2106
2260
|
[File.expand_path('~/.rdbgrc.rb'), true],
|
@@ -2200,6 +2354,7 @@ module DEBUGGER__
|
|
2200
2354
|
def self.log level, msg
|
2201
2355
|
if check_loglevel level
|
2202
2356
|
@logfile = STDERR unless defined? @logfile
|
2357
|
+
return if @logfile.closed?
|
2203
2358
|
|
2204
2359
|
if defined? SESSION
|
2205
2360
|
pi = SESSION.process_info
|
@@ -2282,8 +2437,24 @@ module DEBUGGER__
|
|
2282
2437
|
end
|
2283
2438
|
end
|
2284
2439
|
|
2285
|
-
|
2286
|
-
|
2440
|
+
module DaemonInterceptor
|
2441
|
+
def daemon
|
2442
|
+
return super unless defined?(SESSION) && SESSION.active?
|
2443
|
+
|
2444
|
+
_, child_hook = __fork_setup_for_debugger(:child)
|
2445
|
+
|
2446
|
+
unless SESSION.remote?
|
2447
|
+
DEBUGGER__.warn "Can't debug the code after Process.daemon locally. Use the remote debugging feature."
|
2448
|
+
end
|
2449
|
+
|
2450
|
+
super.tap do
|
2451
|
+
child_hook.call
|
2452
|
+
end
|
2453
|
+
end
|
2454
|
+
end
|
2455
|
+
|
2456
|
+
private def __fork_setup_for_debugger fork_mode = nil
|
2457
|
+
fork_mode ||= CONFIG[:fork_mode]
|
2287
2458
|
|
2288
2459
|
if fork_mode == :both && CONFIG[:parent_on_fork]
|
2289
2460
|
fork_mode = :parent
|
@@ -2298,19 +2469,19 @@ module DEBUGGER__
|
|
2298
2469
|
# Do nothing
|
2299
2470
|
}
|
2300
2471
|
child_hook = -> {
|
2301
|
-
DEBUGGER__.
|
2472
|
+
DEBUGGER__.info "Detaching after fork from child process #{Process.pid}"
|
2302
2473
|
SESSION.deactivate
|
2303
2474
|
}
|
2304
2475
|
when :child
|
2305
2476
|
SESSION.before_fork false
|
2306
2477
|
|
2307
2478
|
parent_hook = -> child_pid {
|
2308
|
-
DEBUGGER__.
|
2479
|
+
DEBUGGER__.info "Detaching after fork from parent process #{Process.pid}"
|
2309
2480
|
SESSION.after_fork_parent
|
2310
2481
|
SESSION.deactivate
|
2311
2482
|
}
|
2312
2483
|
child_hook = -> {
|
2313
|
-
DEBUGGER__.
|
2484
|
+
DEBUGGER__.info "Attaching after process #{parent_pid} fork to child process #{Process.pid}"
|
2314
2485
|
SESSION.activate on_fork: true
|
2315
2486
|
}
|
2316
2487
|
when :both
|
@@ -2321,7 +2492,7 @@ module DEBUGGER__
|
|
2321
2492
|
SESSION.after_fork_parent
|
2322
2493
|
}
|
2323
2494
|
child_hook = -> {
|
2324
|
-
DEBUGGER__.
|
2495
|
+
DEBUGGER__.info "Attaching after process #{parent_pid} fork to child process #{Process.pid}"
|
2325
2496
|
SESSION.process_group.after_fork child: true
|
2326
2497
|
SESSION.activate on_fork: true
|
2327
2498
|
}
|
@@ -2348,6 +2519,7 @@ module DEBUGGER__
|
|
2348
2519
|
module ::Process
|
2349
2520
|
class << self
|
2350
2521
|
prepend ForkInterceptor
|
2522
|
+
prepend DaemonInterceptor
|
2351
2523
|
end
|
2352
2524
|
end
|
2353
2525
|
|
@@ -2383,6 +2555,7 @@ module DEBUGGER__
|
|
2383
2555
|
module ::Process
|
2384
2556
|
class << self
|
2385
2557
|
prepend ForkInterceptor
|
2558
|
+
prepend DaemonInterceptor
|
2386
2559
|
end
|
2387
2560
|
end
|
2388
2561
|
end
|
@@ -2399,10 +2572,17 @@ module Kernel
|
|
2399
2572
|
return if !defined?(::DEBUGGER__::SESSION) || !::DEBUGGER__::SESSION.active?
|
2400
2573
|
|
2401
2574
|
if pre || (do_expr = binding.local_variable_get(:do))
|
2402
|
-
cmds = ['
|
2575
|
+
cmds = ['#debugger', pre, do_expr]
|
2403
2576
|
end
|
2404
2577
|
|
2405
|
-
|
2578
|
+
if ::DEBUGGER__::SESSION.in_subsession?
|
2579
|
+
if cmds
|
2580
|
+
commands = [*cmds[1], *cmds[2]].map{|c| c.split(';;').join("\n")}
|
2581
|
+
::DEBUGGER__::SESSION.add_preset_commands cmds[0], commands, kick: false, continue: false
|
2582
|
+
end
|
2583
|
+
else
|
2584
|
+
loc = caller_locations(up_level, 1).first; ::DEBUGGER__.add_line_breakpoint loc.path, loc.lineno + 1, oneshot: true, command: cmds
|
2585
|
+
end
|
2406
2586
|
self
|
2407
2587
|
end
|
2408
2588
|
|