debug 1.6.3 → 1.7.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 +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
|
|