debug 1.0.0.beta7 → 1.0.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 +108 -106
- data/Gemfile +1 -0
- data/README.md +415 -250
- data/Rakefile +2 -1
- data/TODO.md +3 -8
- data/debug.gemspec +1 -0
- data/exe/rdbg +5 -8
- data/ext/debug/debug.c +11 -1
- data/lib/debug/breakpoint.rb +55 -22
- data/lib/debug/client.rb +7 -12
- data/lib/debug/color.rb +19 -4
- data/lib/debug/config.rb +354 -175
- data/lib/debug/console.rb +75 -70
- data/lib/debug/frame_info.rb +40 -7
- data/lib/debug/local.rb +91 -0
- data/lib/debug/open.rb +1 -1
- data/lib/debug/open_nonstop.rb +15 -0
- data/lib/debug/server.rb +74 -30
- data/lib/debug/server_dap.rb +32 -7
- data/lib/debug/session.rb +584 -299
- data/lib/debug/{run.rb → start.rb} +1 -1
- data/lib/debug/thread_client.rb +620 -162
- data/lib/debug/tracer.rb +242 -0
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +335 -227
- metadata +22 -5
data/lib/debug/console.rb
CHANGED
|
@@ -1,66 +1,87 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
module DEBUGGER__
|
|
3
|
+
class Console
|
|
4
|
+
begin
|
|
5
|
+
raise LoadError if CONFIG[:no_reline]
|
|
6
|
+
require 'reline'
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
8
|
+
# reline 0.2.7 or later is required.
|
|
9
|
+
raise LoadError if Reline::VERSION < '0.2.6'
|
|
5
10
|
|
|
6
|
-
|
|
11
|
+
require_relative 'color'
|
|
12
|
+
include Color
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
# 0.2.7 has SIGWINCH issue on non-main thread
|
|
15
|
+
class ::Reline::LineEditor
|
|
16
|
+
m = Module.new do
|
|
17
|
+
def reset(prompt = '', encoding:)
|
|
18
|
+
super
|
|
19
|
+
Signal.trap(:SIGWINCH, nil)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
prepend m
|
|
15
23
|
end
|
|
16
|
-
end
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
trap(:SIGINT, @prev_handler)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
25
|
+
def readline_setup prompt
|
|
26
|
+
commands = DEBUGGER__.commands
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
Reline.completion_proc = -> given do
|
|
29
|
+
buff = Reline.line_buffer
|
|
30
|
+
Reline.completion_append_character= ' '
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if /\s/ =~ buff # second parameters
|
|
33
|
+
given = File.expand_path(given + 'a').sub(/a\z/, '')
|
|
34
|
+
files = Dir.glob(given + '*')
|
|
35
|
+
if files.size == 1 && File.directory?(files.first)
|
|
36
|
+
Reline.completion_append_character= '/'
|
|
37
|
+
end
|
|
38
|
+
files
|
|
39
|
+
else
|
|
40
|
+
commands.keys.grep(/\A#{given}/)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
end
|
|
44
|
+
Reline.output_modifier_proc = -> buff, **kw do
|
|
45
|
+
c, rest = get_command buff
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
case
|
|
48
|
+
when commands.keys.include?(c = c.strip)
|
|
49
|
+
# [:DIM, :CYAN, :BLUE, :CLEAR, :UNDERLINE, :REVERSE, :RED, :GREEN, :MAGENTA, :BOLD, :YELLOW]
|
|
50
|
+
cmd = colorize(c.strip, [:CYAN, :UNDERLINE])
|
|
51
|
+
|
|
52
|
+
if commands[c] == c
|
|
53
|
+
rprompt = colorize(" # command", [:DIM])
|
|
54
|
+
else
|
|
55
|
+
rprompt = colorize(" # #{commands[c]} command", [:DIM])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
rest = (rest ? colorize_code(rest) : '') + rprompt
|
|
59
|
+
cmd + rest
|
|
60
|
+
when !rest && /\A\s*[a-z]*\z/ =~ c
|
|
61
|
+
buff
|
|
62
|
+
else
|
|
63
|
+
colorize_code(buff.chomp) + colorize(" # ruby", [:DIM])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
44
66
|
end
|
|
45
|
-
end
|
|
46
67
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
private def get_command line
|
|
69
|
+
case line.chomp
|
|
70
|
+
when /\A(\s*[a-z]+)(\s.*)?\z$/
|
|
71
|
+
return $1, $2
|
|
72
|
+
else
|
|
73
|
+
line.chomp
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def readline prompt
|
|
78
|
+
readline_setup prompt
|
|
79
|
+
Reline.readmultiline(prompt, true){ true }
|
|
59
80
|
end
|
|
60
|
-
end
|
|
61
81
|
|
|
82
|
+
rescue LoadError
|
|
62
83
|
begin
|
|
63
|
-
require 'readline'
|
|
84
|
+
require 'readline.so'
|
|
64
85
|
|
|
65
86
|
def readline_setup
|
|
66
87
|
Readline.completion_proc = proc{|given|
|
|
@@ -75,38 +96,22 @@ module DEBUGGER__
|
|
|
75
96
|
end
|
|
76
97
|
files
|
|
77
98
|
else
|
|
78
|
-
DEBUGGER__.commands.grep(/\A#{given}/)
|
|
99
|
+
DEBUGGER__.commands.keys.grep(/\A#{given}/)
|
|
79
100
|
end
|
|
80
101
|
}
|
|
81
102
|
end
|
|
82
103
|
|
|
83
|
-
def
|
|
104
|
+
def readline prompt
|
|
84
105
|
readline_setup
|
|
85
|
-
Readline.readline(
|
|
106
|
+
Readline.readline(prompt, true)
|
|
86
107
|
end
|
|
108
|
+
|
|
87
109
|
rescue LoadError
|
|
88
|
-
def
|
|
89
|
-
print
|
|
110
|
+
def readline prompt
|
|
111
|
+
print prompt
|
|
90
112
|
gets
|
|
91
113
|
end
|
|
92
114
|
end
|
|
93
|
-
|
|
94
|
-
def readline
|
|
95
|
-
setup_interrupt do
|
|
96
|
-
(readline_body || 'quit').strip
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def setup_interrupt
|
|
101
|
-
current_thread = Thread.current # should be session_server thread
|
|
102
|
-
|
|
103
|
-
prev_handler = trap(:INT){
|
|
104
|
-
current_thread.raise Interrupt
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
yield
|
|
108
|
-
ensure
|
|
109
|
-
trap(:INT, prev_handler)
|
|
110
115
|
end
|
|
111
116
|
end
|
|
112
117
|
end
|
data/lib/debug/frame_info.rb
CHANGED
|
@@ -4,7 +4,9 @@ module DEBUGGER__
|
|
|
4
4
|
FrameInfo = Struct.new(:location, :self, :binding, :iseq, :class, :frame_depth,
|
|
5
5
|
:has_return_value, :return_value,
|
|
6
6
|
:has_raised_exception, :raised_exception,
|
|
7
|
-
:show_line
|
|
7
|
+
:show_line,
|
|
8
|
+
:_local_variables, :_callee # for recorder
|
|
9
|
+
)
|
|
8
10
|
|
|
9
11
|
# extend FrameInfo with debug.so
|
|
10
12
|
if File.exist? File.join(__dir__, 'debug.so')
|
|
@@ -25,10 +27,10 @@ module DEBUGGER__
|
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def pretty_path
|
|
28
|
-
use_short_path =
|
|
30
|
+
use_short_path = CONFIG[:use_short_path]
|
|
29
31
|
|
|
30
32
|
case
|
|
31
|
-
when use_short_path && path.start_with?(dir =
|
|
33
|
+
when use_short_path && path.start_with?(dir = CONFIG["rubylibdir"] + '/')
|
|
32
34
|
path.sub(dir, '$(rubylibdir)/')
|
|
33
35
|
when use_short_path && Gem.path.any? do |gp|
|
|
34
36
|
path.start_with?(dir = gp + '/gems/')
|
|
@@ -62,7 +64,7 @@ module DEBUGGER__
|
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def frame_type
|
|
65
|
-
if
|
|
67
|
+
if self.local_variables && iseq
|
|
66
68
|
if iseq.type == :block
|
|
67
69
|
:block
|
|
68
70
|
elsif callee
|
|
@@ -102,11 +104,11 @@ module DEBUGGER__
|
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
def callee
|
|
105
|
-
|
|
107
|
+
self._callee ||= self.binding&.eval('__callee__')
|
|
106
108
|
end
|
|
107
109
|
|
|
108
110
|
def return_str
|
|
109
|
-
if binding && iseq && has_return_value
|
|
111
|
+
if self.binding && iseq && has_return_value
|
|
110
112
|
DEBUGGER__.short_inspect(return_value)
|
|
111
113
|
end
|
|
112
114
|
end
|
|
@@ -115,6 +117,33 @@ module DEBUGGER__
|
|
|
115
117
|
"#{pretty_path}:#{location.lineno}"
|
|
116
118
|
end
|
|
117
119
|
|
|
120
|
+
private def make_binding
|
|
121
|
+
__newb__ = self.self.instance_eval('binding')
|
|
122
|
+
self.local_variables.each{|var, val|
|
|
123
|
+
__newb__.local_variable_set(var, val)
|
|
124
|
+
}
|
|
125
|
+
__newb__
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def eval_binding
|
|
129
|
+
if b = self.binding
|
|
130
|
+
b
|
|
131
|
+
elsif self.local_variables
|
|
132
|
+
make_binding
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def local_variables
|
|
137
|
+
if lvars = self._local_variables
|
|
138
|
+
lvars
|
|
139
|
+
elsif b = self.binding
|
|
140
|
+
lvars = b.local_variables.map{|var|
|
|
141
|
+
[var, b.local_variable_get(var)]
|
|
142
|
+
}.to_h
|
|
143
|
+
self._local_variables = lvars
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
118
147
|
private
|
|
119
148
|
|
|
120
149
|
def get_singleton_class obj
|
|
@@ -123,11 +152,15 @@ module DEBUGGER__
|
|
|
123
152
|
nil
|
|
124
153
|
end
|
|
125
154
|
|
|
155
|
+
private def local_variable_get var
|
|
156
|
+
local_variables[var]
|
|
157
|
+
end
|
|
158
|
+
|
|
126
159
|
def parameters_info(argc)
|
|
127
160
|
vars = iseq.locals[0...argc]
|
|
128
161
|
vars.map{|var|
|
|
129
162
|
begin
|
|
130
|
-
{ name: var, value: DEBUGGER__.short_inspect(
|
|
163
|
+
{ name: var, value: DEBUGGER__.short_inspect(local_variable_get(var)) }
|
|
131
164
|
rescue NameError, TypeError
|
|
132
165
|
nil
|
|
133
166
|
end
|
data/lib/debug/local.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'io/console/size'
|
|
4
|
+
require_relative 'console'
|
|
5
|
+
|
|
6
|
+
module DEBUGGER__
|
|
7
|
+
class UI_LocalConsole < UI_Base
|
|
8
|
+
def initialize
|
|
9
|
+
@console = Console.new
|
|
10
|
+
|
|
11
|
+
unless CONFIG[:no_sigint_hook]
|
|
12
|
+
@prev_handler = trap(:SIGINT){
|
|
13
|
+
if SESSION.active?
|
|
14
|
+
ThreadClient.current.on_trap :SIGINT
|
|
15
|
+
end
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def close
|
|
21
|
+
if @prev_handler
|
|
22
|
+
trap(:SIGINT, @prev_handler)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def remote?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def activate on_fork: false
|
|
31
|
+
# Do nothing
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def deactivate
|
|
35
|
+
# Do nothing
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def width
|
|
39
|
+
if (w = IO.console_size[1]) == 0 # for tests PTY
|
|
40
|
+
80
|
|
41
|
+
else
|
|
42
|
+
w
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def quit n
|
|
47
|
+
exit n
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def ask prompt
|
|
51
|
+
setup_interrupt do
|
|
52
|
+
print prompt
|
|
53
|
+
($stdin.gets || '').strip
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def puts str = nil
|
|
58
|
+
case str
|
|
59
|
+
when Array
|
|
60
|
+
str.each{|line|
|
|
61
|
+
$stdout.puts line.chomp
|
|
62
|
+
}
|
|
63
|
+
when String
|
|
64
|
+
str.each_line{|line|
|
|
65
|
+
$stdout.puts line.chomp
|
|
66
|
+
}
|
|
67
|
+
when nil
|
|
68
|
+
$stdout.puts
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def readline prompt = '(rdbg)'
|
|
73
|
+
setup_interrupt do
|
|
74
|
+
(@console.readline(prompt) || 'quit').strip
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def setup_interrupt
|
|
79
|
+
current_thread = Thread.current # should be session_server thread
|
|
80
|
+
|
|
81
|
+
prev_handler = trap(:INT){
|
|
82
|
+
current_thread.raise Interrupt
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
yield
|
|
86
|
+
ensure
|
|
87
|
+
trap(:INT, prev_handler)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
data/lib/debug/open.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Open the door for the debugger to connect.
|
|
4
|
+
# Unlike debug/open, it does not stop at the beginning of the program.
|
|
5
|
+
# Users can connect to debuggee program with "rdbg --attach" option or
|
|
6
|
+
# VSCode attach type.
|
|
7
|
+
#
|
|
8
|
+
# If RUBY_DEBUG_PORT envval is provided (digits), open TCP/IP port.
|
|
9
|
+
# Otherwise, UNIX domain socket is used.
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
require_relative 'session'
|
|
13
|
+
return unless defined?(DEBUGGER__)
|
|
14
|
+
|
|
15
|
+
DEBUGGER__.open(nonstop: true)
|
data/lib/debug/server.rb
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'socket'
|
|
4
|
-
|
|
5
|
-
require_relative 'session'
|
|
6
|
-
return unless defined?(DEBUGGER__)
|
|
7
|
-
|
|
8
4
|
require_relative 'config'
|
|
9
5
|
require_relative 'version'
|
|
10
6
|
|
|
11
7
|
module DEBUGGER__
|
|
12
8
|
class UI_ServerBase < UI_Base
|
|
13
9
|
def initialize
|
|
14
|
-
@sock = nil
|
|
10
|
+
@sock = @sock_for_fork = nil
|
|
15
11
|
@accept_m = Mutex.new
|
|
16
12
|
@accept_cv = ConditionVariable.new
|
|
17
13
|
@client_addr = nil
|
|
@@ -20,11 +16,33 @@ module DEBUGGER__
|
|
|
20
16
|
@unsent_messages = []
|
|
21
17
|
@width = 80
|
|
22
18
|
|
|
19
|
+
activate
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Terminate < StandardError
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def deactivate
|
|
26
|
+
@reader_thread.raise Terminate
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def accept
|
|
30
|
+
if @sock_for_fork
|
|
31
|
+
begin
|
|
32
|
+
yield @sock_for_fork, already_connected: true
|
|
33
|
+
ensure
|
|
34
|
+
@sock_for_fork.close
|
|
35
|
+
@sock_for_fork = nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def activate on_fork: false
|
|
23
41
|
@reader_thread = Thread.new do
|
|
24
42
|
# An error on this thread should break the system.
|
|
25
43
|
Thread.current.abort_on_exception = true
|
|
26
44
|
|
|
27
|
-
accept do |server|
|
|
45
|
+
accept do |server, already_connected: false|
|
|
28
46
|
DEBUGGER__.warn "Connected."
|
|
29
47
|
|
|
30
48
|
@accept_m.synchronize{
|
|
@@ -41,14 +59,17 @@ module DEBUGGER__
|
|
|
41
59
|
|
|
42
60
|
@q_msg = Queue.new
|
|
43
61
|
@q_ans = Queue.new
|
|
44
|
-
}
|
|
62
|
+
} unless already_connected
|
|
45
63
|
|
|
46
64
|
setup_interrupt do
|
|
65
|
+
pause unless already_connected
|
|
47
66
|
process
|
|
48
67
|
end
|
|
49
68
|
|
|
69
|
+
rescue Terminate
|
|
70
|
+
raise # should catch at outer scope
|
|
50
71
|
rescue => e
|
|
51
|
-
DEBUGGER__.warn "ReaderThreadError: #{e}"
|
|
72
|
+
DEBUGGER__.warn "ReaderThreadError: #{e}"
|
|
52
73
|
ensure
|
|
53
74
|
DEBUGGER__.warn "Disconnected."
|
|
54
75
|
@sock = nil
|
|
@@ -56,7 +77,10 @@ module DEBUGGER__
|
|
|
56
77
|
@q_msg = nil
|
|
57
78
|
@q_ans.close
|
|
58
79
|
@q_ans = nil
|
|
59
|
-
end
|
|
80
|
+
end # accept
|
|
81
|
+
|
|
82
|
+
rescue Terminate
|
|
83
|
+
# ignore
|
|
60
84
|
end
|
|
61
85
|
end
|
|
62
86
|
|
|
@@ -88,8 +112,6 @@ module DEBUGGER__
|
|
|
88
112
|
end
|
|
89
113
|
|
|
90
114
|
def process
|
|
91
|
-
pause
|
|
92
|
-
|
|
93
115
|
while line = @sock.gets
|
|
94
116
|
case line
|
|
95
117
|
when /\Apause/
|
|
@@ -133,10 +155,6 @@ module DEBUGGER__
|
|
|
133
155
|
trap(:SIGINT, prev_handler)
|
|
134
156
|
end
|
|
135
157
|
|
|
136
|
-
def accept
|
|
137
|
-
raise "NOT IMPLEMENTED ERROR"
|
|
138
|
-
end
|
|
139
|
-
|
|
140
158
|
attr_reader :reader_thread
|
|
141
159
|
|
|
142
160
|
class NoRemoteError < Exception; end
|
|
@@ -158,7 +176,7 @@ module DEBUGGER__
|
|
|
158
176
|
until s = @sock
|
|
159
177
|
@accept_m.synchronize{
|
|
160
178
|
unless @sock
|
|
161
|
-
DEBUGGER__.warn "wait for
|
|
179
|
+
DEBUGGER__.warn "wait for debugger connection..."
|
|
162
180
|
@accept_cv.wait(@accept_m)
|
|
163
181
|
end
|
|
164
182
|
}
|
|
@@ -199,12 +217,15 @@ module DEBUGGER__
|
|
|
199
217
|
end
|
|
200
218
|
end
|
|
201
219
|
|
|
202
|
-
def readline
|
|
203
|
-
(sock do |s|
|
|
220
|
+
def readline prompt
|
|
221
|
+
input = (sock do |s|
|
|
204
222
|
s.puts "input"
|
|
205
223
|
sleep 0.01 until @q_msg
|
|
224
|
+
|
|
206
225
|
@q_msg.pop
|
|
207
226
|
end || 'continue').strip
|
|
227
|
+
|
|
228
|
+
input
|
|
208
229
|
end
|
|
209
230
|
|
|
210
231
|
def pause
|
|
@@ -222,9 +243,9 @@ module DEBUGGER__
|
|
|
222
243
|
|
|
223
244
|
class UI_TcpServer < UI_ServerBase
|
|
224
245
|
def initialize host: nil, port: nil
|
|
225
|
-
@host = host ||
|
|
246
|
+
@host = host || CONFIG[:host] || '127.0.0.1'
|
|
226
247
|
@port = port || begin
|
|
227
|
-
port_str =
|
|
248
|
+
port_str = CONFIG[:port] || raise("Specify listening port by RUBY_DEBUG_PORT environment variable.")
|
|
228
249
|
if /\A\d+\z/ !~ port_str
|
|
229
250
|
raise "Specify digits for port number"
|
|
230
251
|
else
|
|
@@ -236,17 +257,34 @@ module DEBUGGER__
|
|
|
236
257
|
end
|
|
237
258
|
|
|
238
259
|
def accept
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
260
|
+
retry_cnt = 0
|
|
261
|
+
super # for fork
|
|
262
|
+
|
|
263
|
+
begin
|
|
264
|
+
Socket.tcp_server_sockets @host, @port do |socks|
|
|
265
|
+
::DEBUGGER__.warn "Debugger can attach via TCP/IP (#{socks.map{|e| e.local_address.inspect}})"
|
|
266
|
+
Socket.accept_loop(socks) do |sock, client|
|
|
267
|
+
@client_addr = client
|
|
268
|
+
yield @sock_for_fork = sock
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
rescue Errno::EADDRINUSE
|
|
272
|
+
if retry_cnt < 10
|
|
273
|
+
retry_cnt += 1
|
|
274
|
+
sleep 0.1
|
|
275
|
+
retry
|
|
276
|
+
else
|
|
277
|
+
raise
|
|
244
278
|
end
|
|
279
|
+
rescue Terminate
|
|
280
|
+
# OK
|
|
281
|
+
rescue => e
|
|
282
|
+
$stderr.puts e.inspect, e.message
|
|
283
|
+
pp e.backtrace
|
|
284
|
+
exit
|
|
245
285
|
end
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
pp e.backtrace
|
|
249
|
-
exit
|
|
286
|
+
ensure
|
|
287
|
+
@sock_for_fork = nil
|
|
250
288
|
end
|
|
251
289
|
end
|
|
252
290
|
|
|
@@ -254,14 +292,17 @@ module DEBUGGER__
|
|
|
254
292
|
def initialize sock_dir: nil, sock_path: nil
|
|
255
293
|
@sock_path = sock_path
|
|
256
294
|
@sock_dir = sock_dir || DEBUGGER__.unix_domain_socket_dir
|
|
295
|
+
@sock_for_fork = nil
|
|
257
296
|
|
|
258
297
|
super()
|
|
259
298
|
end
|
|
260
299
|
|
|
261
300
|
def accept
|
|
301
|
+
super # for fork
|
|
302
|
+
|
|
262
303
|
case
|
|
263
304
|
when @sock_path
|
|
264
|
-
when sp =
|
|
305
|
+
when sp = CONFIG[:sock_path]
|
|
265
306
|
@sock_path = sp
|
|
266
307
|
else
|
|
267
308
|
@sock_path = DEBUGGER__.create_unix_domain_socket_name(@sock_dir)
|
|
@@ -269,10 +310,13 @@ module DEBUGGER__
|
|
|
269
310
|
|
|
270
311
|
::DEBUGGER__.warn "Debugger can attach via UNIX domain socket (#{@sock_path})"
|
|
271
312
|
Socket.unix_server_loop @sock_path do |sock, client|
|
|
313
|
+
@sock_for_fork = sock
|
|
272
314
|
@client_addr = client
|
|
315
|
+
|
|
273
316
|
yield sock
|
|
274
317
|
ensure
|
|
275
318
|
sock.close
|
|
319
|
+
@sock_for_fork = nil
|
|
276
320
|
end
|
|
277
321
|
end
|
|
278
322
|
end
|