debug 1.0.0.beta4 → 1.0.0.beta5
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/.github/workflows/ruby.yml +34 -0
- data/.gitignore +1 -0
- data/CONTRIBUTING.md +48 -0
- data/Gemfile +1 -1
- data/README.md +72 -37
- data/debug.gemspec +2 -0
- data/exe/rdbg +8 -1
- data/ext/debug/debug.c +9 -8
- data/lib/debug/breakpoint.rb +71 -24
- data/lib/debug/client.rb +49 -6
- data/lib/debug/color.rb +70 -0
- data/lib/debug/config.rb +39 -5
- data/lib/debug/console.rb +8 -1
- data/lib/debug/frame_info.rb +61 -30
- data/lib/debug/open.rb +2 -0
- data/lib/debug/run.rb +2 -0
- data/lib/debug/server.rb +72 -19
- data/lib/debug/server_dap.rb +605 -0
- data/lib/debug/session.rb +181 -86
- data/lib/debug/source_repository.rb +53 -33
- data/lib/debug/test_console.rb +0 -0
- data/lib/debug/thread_client.rb +91 -23
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +51 -28
- metadata +21 -3
data/lib/debug/client.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'io/console/size'
|
3
|
+
|
2
4
|
require_relative 'config'
|
5
|
+
require_relative 'version'
|
6
|
+
|
7
|
+
# $VERBOSE = true
|
3
8
|
|
4
9
|
module DEBUGGER__
|
5
10
|
class CommandLineOptionError < Exception; end
|
@@ -18,6 +23,8 @@ module DEBUGGER__
|
|
18
23
|
end
|
19
24
|
|
20
25
|
def initialize argv
|
26
|
+
return util(argv) if String === argv
|
27
|
+
|
21
28
|
case argv.size
|
22
29
|
when 0
|
23
30
|
connect_unix
|
@@ -36,6 +43,23 @@ module DEBUGGER__
|
|
36
43
|
else
|
37
44
|
raise CommandLineOptionError
|
38
45
|
end
|
46
|
+
|
47
|
+
@width = IO.console_size[1]
|
48
|
+
@width_changed = false
|
49
|
+
|
50
|
+
send "version: #{VERSION} width: #{@width} cookie: #{CONFIG[:cookie]}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def util name
|
54
|
+
case name
|
55
|
+
when 'gen-sockpath'
|
56
|
+
puts DEBUGGER__.create_unix_domain_socket_name
|
57
|
+
when 'list-socks'
|
58
|
+
cleanup_unix_domain_sockets
|
59
|
+
puts list_connections
|
60
|
+
else
|
61
|
+
raise "Unknown utility: #{name}"
|
62
|
+
end
|
39
63
|
end
|
40
64
|
|
41
65
|
def cleanup_unix_domain_sockets
|
@@ -50,16 +74,20 @@ module DEBUGGER__
|
|
50
74
|
end
|
51
75
|
end
|
52
76
|
|
77
|
+
def list_connections
|
78
|
+
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*')
|
79
|
+
end
|
80
|
+
|
53
81
|
def connect_unix name = nil
|
54
82
|
if name
|
55
83
|
if File.exist? name
|
56
84
|
@s = Socket.unix(name)
|
57
85
|
else
|
58
|
-
@s = Socket.unix(File.join(DEBUGGER__.
|
86
|
+
@s = Socket.unix(File.join(DEBUGGER__.unix_domain_socket_dir, name))
|
59
87
|
end
|
60
88
|
else
|
61
89
|
cleanup_unix_domain_sockets
|
62
|
-
files =
|
90
|
+
files = list_connections
|
63
91
|
case files.size
|
64
92
|
when 0
|
65
93
|
$stderr.puts "No debug session is available."
|
@@ -80,13 +108,22 @@ module DEBUGGER__
|
|
80
108
|
@s = Socket.tcp(host, port)
|
81
109
|
end
|
82
110
|
|
111
|
+
def send msg
|
112
|
+
p send: msg if $VERBOSE
|
113
|
+
@s.puts msg
|
114
|
+
end
|
115
|
+
|
83
116
|
def connect
|
84
117
|
trap(:SIGINT){
|
85
|
-
|
118
|
+
send "pause"
|
119
|
+
}
|
120
|
+
trap(:SIGWINCH){
|
121
|
+
@width = IO.console_size[1]
|
122
|
+
@width_changed = true
|
86
123
|
}
|
87
124
|
|
88
125
|
while line = @s.gets
|
89
|
-
|
126
|
+
p recv: line if $VERBOSE
|
90
127
|
case line
|
91
128
|
when /^out (.*)/
|
92
129
|
puts "#{$1}"
|
@@ -102,10 +139,16 @@ module DEBUGGER__
|
|
102
139
|
end
|
103
140
|
|
104
141
|
line = (line || 'quit').strip
|
105
|
-
|
142
|
+
|
143
|
+
if @width_changed
|
144
|
+
@width_changed = false
|
145
|
+
send "width #{@width}"
|
146
|
+
end
|
147
|
+
|
148
|
+
send "command #{line}"
|
106
149
|
when /^ask (.*)/
|
107
150
|
print $1
|
108
|
-
|
151
|
+
send "answer #{gets || ''}"
|
109
152
|
when /^quit/
|
110
153
|
raise 'quit'
|
111
154
|
else
|
data/lib/debug/color.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
begin
|
2
|
+
require 'irb/color'
|
3
|
+
require "irb/color_printer"
|
4
|
+
rescue LoadError
|
5
|
+
warn "DEBUGGER: can not load newer irb for coloring. Write 'gem \"debug\" in your Gemfile."
|
6
|
+
end
|
7
|
+
|
8
|
+
module DEBUGGER__
|
9
|
+
module Color
|
10
|
+
if defined? IRB::Color.colorize
|
11
|
+
def colorize str, color
|
12
|
+
if CONFIG[:use_colorize]
|
13
|
+
IRB::Color.colorize str, color
|
14
|
+
else
|
15
|
+
str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
else
|
19
|
+
def colorize str, color
|
20
|
+
str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if defined? IRB::ColorPrinter.pp
|
25
|
+
def color_pp obj
|
26
|
+
IRB::ColorPrinter.pp(obj, "")
|
27
|
+
end
|
28
|
+
else
|
29
|
+
def color_pp obj
|
30
|
+
obj.pretty_inspect
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def colored_inspect obj
|
35
|
+
if CONFIG[:use_colorize]
|
36
|
+
color_pp obj
|
37
|
+
else
|
38
|
+
obj.pretty_inspect
|
39
|
+
end
|
40
|
+
rescue => ex
|
41
|
+
err_msg = "#{ex.inspect} rescued during inspection"
|
42
|
+
string_result = obj.to_s rescue nil
|
43
|
+
|
44
|
+
# don't colorize the string here because it's not from user's application
|
45
|
+
if string_result
|
46
|
+
%Q{"#{string_result}" from #to_s because #{err_msg}}
|
47
|
+
else
|
48
|
+
err_msg
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if defined? IRB::Color.colorize_code
|
53
|
+
def colorize_code code
|
54
|
+
IRB::Color.colorize_code(code)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
def colorize_code code
|
58
|
+
code
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def colorize_cyan(str)
|
63
|
+
colorize(str, [:CYAN, :BOLD])
|
64
|
+
end
|
65
|
+
|
66
|
+
def colorize_blue(str)
|
67
|
+
colorize(str, [:BLUE, :BOLD])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/debug/config.rb
CHANGED
@@ -47,6 +47,7 @@ module DEBUGGER__
|
|
47
47
|
host: 'RUBY_DEBUG_HOST', # TCP/IP remote debugging: host (localhost if not given)
|
48
48
|
sock_path: 'RUBY_DEBUG_SOCK_PATH', # UNIX Domain Socket remote debugging: socket path
|
49
49
|
sock_dir: 'RUBY_DEBUG_SOCK_DIR', # UNIX Domain Socket remote debugging: socket directory
|
50
|
+
cookie: 'RUBY_DEBUG_COOKIE', # Cookie for negotiation
|
50
51
|
}.freeze
|
51
52
|
|
52
53
|
def self.config_to_env config
|
@@ -77,35 +78,46 @@ module DEBUGGER__
|
|
77
78
|
return config if !argv || argv.empty?
|
78
79
|
|
79
80
|
require 'optparse'
|
81
|
+
require_relative 'version'
|
80
82
|
|
81
83
|
opt = OptionParser.new do |o|
|
82
84
|
o.banner = "#{$0} [options] -- [debuggee options]"
|
83
85
|
o.separator ''
|
86
|
+
o.version = ::DEBUGGER__::VERSION
|
84
87
|
|
85
88
|
o.separator 'Debug console mode:'
|
86
89
|
o.on('-n', '--nonstop', 'Do not stop at the beginning of the script.') do
|
87
90
|
config[:nonstop] = '1'
|
88
91
|
end
|
89
92
|
|
90
|
-
o.on('-e
|
93
|
+
o.on('-e COMMAND', 'execute debug command at the beginning of the script.') do |cmd|
|
91
94
|
config[:commands] ||= ''
|
92
95
|
config[:commands] << cmd + ';;'
|
93
96
|
end
|
94
97
|
|
95
|
-
o.on('-
|
98
|
+
o.on('-x FILE', '--init-script=FILE', 'execute debug command in the FILE.') do |file|
|
99
|
+
config[:init_script] = file
|
100
|
+
end
|
101
|
+
|
102
|
+
o.separator ''
|
103
|
+
|
104
|
+
o.on('-O', '--open', 'Start remote debugging with opening the network port.',
|
96
105
|
'If TCP/IP options are not given,',
|
97
106
|
'a UNIX domain socket will be used.') do
|
98
107
|
config[:remote] = true
|
99
108
|
end
|
100
|
-
o.on('--sock-path=
|
109
|
+
o.on('--sock-path=SOCK_PATH', 'UNIX Doman socket path') do |path|
|
101
110
|
config[:sock_path] = path
|
102
111
|
end
|
103
|
-
o.on('--port=
|
112
|
+
o.on('--port=PORT', 'Listening TCP/IP port') do |port|
|
104
113
|
config[:port] = port
|
105
114
|
end
|
106
|
-
o.on('--host=
|
115
|
+
o.on('--host=HOST', 'Listening TCP/IP host') do |host|
|
107
116
|
config[:host] = host
|
108
117
|
end
|
118
|
+
o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c|
|
119
|
+
config[:cookie] = c
|
120
|
+
end
|
109
121
|
|
110
122
|
rdbg = 'rdbg'
|
111
123
|
|
@@ -133,6 +145,28 @@ module DEBUGGER__
|
|
133
145
|
o.separator " '#{rdbg} -A path' tries to connect via UNIX domain socket with given path name."
|
134
146
|
o.separator " '#{rdbg} -A port' tries to connect to localhost:port via TCP/IP."
|
135
147
|
o.separator " '#{rdbg} -A host port' tries to connect to host:port via TCP/IP."
|
148
|
+
|
149
|
+
o.separator ''
|
150
|
+
o.separator 'Other options:'
|
151
|
+
|
152
|
+
o.on("-h", "--help", "Print help") do
|
153
|
+
puts o
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
o.on('-c', '--command', 'Command mode (first argument is command name)') do
|
158
|
+
config[:command] = true
|
159
|
+
end
|
160
|
+
|
161
|
+
o.on('--util=NAME', 'Utility mode (used by tools)') do |name|
|
162
|
+
Client.new(name)
|
163
|
+
exit
|
164
|
+
end
|
165
|
+
|
166
|
+
o.separator ''
|
167
|
+
o.separator 'NOTE'
|
168
|
+
o.separator ' All messages communicated between a debugger and a debuggee are *NOT* encrypted.'
|
169
|
+
o.separator ' Please use the remote debugging feature carefully.'
|
136
170
|
end
|
137
171
|
|
138
172
|
opt.parse!(argv)
|
data/lib/debug/console.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require_relative 'session'
|
2
|
+
return unless defined?(DEBUGGER__)
|
3
|
+
|
4
|
+
require 'io/console/size'
|
2
5
|
|
3
6
|
module DEBUGGER__
|
4
|
-
class UI_Console
|
7
|
+
class UI_Console < UI_Base
|
5
8
|
def initialize
|
6
9
|
end
|
7
10
|
|
@@ -9,6 +12,10 @@ module DEBUGGER__
|
|
9
12
|
false
|
10
13
|
end
|
11
14
|
|
15
|
+
def width
|
16
|
+
IO.console_size[1]
|
17
|
+
end
|
18
|
+
|
12
19
|
def quit n
|
13
20
|
exit n
|
14
21
|
end
|
data/lib/debug/frame_info.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
module DEBUGGER__
|
3
3
|
FrameInfo = Struct.new(:location, :self, :binding, :iseq, :class, :frame_depth,
|
4
|
-
:has_return_value, :return_value,
|
5
|
-
|
4
|
+
:has_return_value, :return_value,
|
5
|
+
:has_raised_exception, :raised_exception,
|
6
|
+
:show_line)
|
6
7
|
|
7
8
|
# extend FrameInfo with debug.so
|
8
9
|
if File.exist? File.join(__dir__, 'debug.so')
|
@@ -39,33 +40,73 @@ module DEBUGGER__
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
43
|
+
def name
|
44
|
+
# p frame_type: frame_type, self: self
|
45
|
+
case frame_type
|
46
|
+
when :block
|
47
|
+
level, block_loc, _args = block_identifier
|
48
|
+
"block in #{block_loc}#{level}"
|
49
|
+
when :method
|
50
|
+
ci, _args = method_identifier
|
51
|
+
"#{ci}"
|
52
|
+
when :c
|
53
|
+
c_identifier
|
54
|
+
when :other
|
55
|
+
other_identifier
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
42
59
|
def file_lines
|
43
|
-
SESSION.source(
|
60
|
+
SESSION.source(self.iseq)
|
44
61
|
end
|
45
62
|
|
46
|
-
def
|
63
|
+
def frame_type
|
47
64
|
if binding && iseq
|
48
65
|
if iseq.type == :block
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
location.label.sub('block'){ "block#{args_str}" }
|
55
|
-
elsif (callee = binding.eval('__callee__', __FILE__, __LINE__)) && (argc = iseq.argc) > 0
|
56
|
-
args = parameters_info iseq.locals[0...argc]
|
57
|
-
"#{klass_sig}#{callee}(#{args})"
|
66
|
+
:block
|
67
|
+
elsif callee
|
68
|
+
:method
|
58
69
|
else
|
59
|
-
|
70
|
+
:other
|
60
71
|
end
|
61
72
|
else
|
62
|
-
|
73
|
+
:c
|
63
74
|
end
|
64
75
|
end
|
65
76
|
|
77
|
+
BLOCK_LABL_REGEXP = /\Ablock( \(\d+ levels\))* in (.+)\z/
|
78
|
+
|
79
|
+
def block_identifier
|
80
|
+
return unless frame_type == :block
|
81
|
+
args = parameters_info(iseq.argc)
|
82
|
+
_, level, block_loc = location.label.match(BLOCK_LABL_REGEXP).to_a
|
83
|
+
[level || "", block_loc, args]
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_identifier
|
87
|
+
return unless frame_type == :method
|
88
|
+
args = parameters_info(iseq.argc)
|
89
|
+
ci = "#{klass_sig}#{callee}"
|
90
|
+
[ci, args]
|
91
|
+
end
|
92
|
+
|
93
|
+
def c_identifier
|
94
|
+
return unless frame_type == :c
|
95
|
+
"[C] #{klass_sig}#{location.base_label}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def other_identifier
|
99
|
+
return unless frame_type == :other
|
100
|
+
location.label
|
101
|
+
end
|
102
|
+
|
103
|
+
def callee
|
104
|
+
@callee ||= binding&.eval('__callee__', __FILE__, __LINE__)
|
105
|
+
end
|
106
|
+
|
66
107
|
def return_str
|
67
108
|
if binding && iseq && has_return_value
|
68
|
-
short_inspect(return_value)
|
109
|
+
DEBUGGER__.short_inspect(return_value)
|
69
110
|
end
|
70
111
|
end
|
71
112
|
|
@@ -75,31 +116,21 @@ module DEBUGGER__
|
|
75
116
|
|
76
117
|
private
|
77
118
|
|
78
|
-
SHORT_INSPECT_LENGTH = 40
|
79
|
-
|
80
|
-
def short_inspect obj
|
81
|
-
str = obj.inspect
|
82
|
-
if str.length > SHORT_INSPECT_LENGTH
|
83
|
-
str[0...SHORT_INSPECT_LENGTH] + '...'
|
84
|
-
else
|
85
|
-
str
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
119
|
def get_singleton_class obj
|
90
120
|
obj.singleton_class # TODO: don't use it
|
91
121
|
rescue TypeError
|
92
122
|
nil
|
93
123
|
end
|
94
124
|
|
95
|
-
def parameters_info
|
125
|
+
def parameters_info(argc)
|
126
|
+
vars = iseq.locals[0...argc]
|
96
127
|
vars.map{|var|
|
97
128
|
begin
|
98
|
-
|
129
|
+
{ name: var, value: DEBUGGER__.short_inspect(binding.local_variable_get(var)) }
|
99
130
|
rescue NameError, TypeError
|
100
131
|
nil
|
101
132
|
end
|
102
|
-
}.compact
|
133
|
+
}.compact
|
103
134
|
end
|
104
135
|
|
105
136
|
def klass_sig
|
data/lib/debug/open.rb
CHANGED
data/lib/debug/run.rb
CHANGED
data/lib/debug/server.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'socket'
|
2
|
+
|
2
3
|
require_relative 'session'
|
4
|
+
return unless defined?(DEBUGGER__)
|
5
|
+
|
3
6
|
require_relative 'config'
|
7
|
+
require_relative 'version'
|
4
8
|
|
5
9
|
module DEBUGGER__
|
6
|
-
class UI_ServerBase
|
10
|
+
class UI_ServerBase < UI_Base
|
7
11
|
def initialize
|
8
12
|
@sock = nil
|
9
13
|
@accept_m = Mutex.new
|
@@ -12,13 +16,19 @@ module DEBUGGER__
|
|
12
16
|
@q_msg = Queue.new
|
13
17
|
@q_ans = Queue.new
|
14
18
|
@unsent_messages = []
|
19
|
+
@width = 80
|
15
20
|
|
16
21
|
@reader_thread = Thread.new do
|
22
|
+
# An error on this thread should break the system.
|
23
|
+
Thread.current.abort_on_exception = true
|
24
|
+
|
17
25
|
accept do |server|
|
18
26
|
DEBUGGER__.message "Connected."
|
19
27
|
|
20
28
|
@accept_m.synchronize{
|
21
29
|
@sock = server
|
30
|
+
greeting
|
31
|
+
|
22
32
|
@accept_cv.signal
|
23
33
|
|
24
34
|
# flush unsent messages
|
@@ -27,26 +37,13 @@ module DEBUGGER__
|
|
27
37
|
}
|
28
38
|
@unsent_messages.clear
|
29
39
|
}
|
30
|
-
@q_msg = Queue.new
|
31
|
-
@q_ans = Queue.new
|
32
40
|
|
33
41
|
setup_interrupt do
|
34
|
-
|
35
|
-
|
36
|
-
while line = @sock.gets
|
37
|
-
case line
|
38
|
-
when /\Apause/
|
39
|
-
pause
|
40
|
-
when /\Acommand ?(.+)/
|
41
|
-
@q_msg << $1
|
42
|
-
when /\Aanswer (.*)/
|
43
|
-
@q_ans << $1
|
44
|
-
else
|
45
|
-
STDERR.puts "unsupported: #{line}"
|
46
|
-
exit!
|
47
|
-
end
|
48
|
-
end
|
42
|
+
process
|
49
43
|
end
|
44
|
+
|
45
|
+
rescue => e
|
46
|
+
DEBUGGER__.message "ReaderThreadError: #{e}"
|
50
47
|
ensure
|
51
48
|
DEBUGGER__.message "Disconnected."
|
52
49
|
@sock = nil
|
@@ -56,10 +53,64 @@ module DEBUGGER__
|
|
56
53
|
end
|
57
54
|
end
|
58
55
|
|
56
|
+
def greeting
|
57
|
+
case g = @sock.gets
|
58
|
+
when /^version:\s+(.+)\s+width: (\d+) cookie:\s+(.*)$/
|
59
|
+
v, w, c = $1, $2, $3
|
60
|
+
# TODO: protocol version
|
61
|
+
if v != VERSION
|
62
|
+
raise "Incompatible version (#{VERSION} client:#{$1})"
|
63
|
+
end
|
64
|
+
|
65
|
+
cookie = CONFIG[:cookie]
|
66
|
+
if cookie && cookie != c
|
67
|
+
raise "Cookie mismatch (#{$2.inspect} was sent)"
|
68
|
+
end
|
69
|
+
|
70
|
+
@width = w.to_i
|
71
|
+
|
72
|
+
when /^Content-Length: (\d+)/
|
73
|
+
require_relative 'server_dap'
|
74
|
+
|
75
|
+
raise unless @sock.read(2) == "\r\n"
|
76
|
+
self.extend(UI_DAP)
|
77
|
+
dap_setup @sock.read($1.to_i)
|
78
|
+
else
|
79
|
+
raise "Greeting message error: #{g}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def process
|
84
|
+
@q_msg = Queue.new
|
85
|
+
@q_ans = Queue.new
|
86
|
+
|
87
|
+
pause
|
88
|
+
|
89
|
+
while line = @sock.gets
|
90
|
+
case line
|
91
|
+
when /\Apause/
|
92
|
+
pause
|
93
|
+
when /\Acommand ?(.+)/
|
94
|
+
@q_msg << $1
|
95
|
+
when /\Aanswer (.*)/
|
96
|
+
@q_ans << $1
|
97
|
+
when /\Awidth (.+)/
|
98
|
+
@width = $1.to_i
|
99
|
+
else
|
100
|
+
STDERR.puts "unsupported: #{line}"
|
101
|
+
exit!
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
59
106
|
def remote?
|
60
107
|
true
|
61
108
|
end
|
62
109
|
|
110
|
+
def width
|
111
|
+
@width
|
112
|
+
end
|
113
|
+
|
63
114
|
def setup_interrupt
|
64
115
|
prev_handler = trap(:SIGINT) do
|
65
116
|
# $stderr.puts "trapped SIGINT"
|
@@ -158,7 +209,7 @@ module DEBUGGER__
|
|
158
209
|
|
159
210
|
class UI_TcpServer < UI_ServerBase
|
160
211
|
def initialize host: nil, port: nil
|
161
|
-
@host = host || ::DEBUGGER__::CONFIG[:host] || '
|
212
|
+
@host = host || ::DEBUGGER__::CONFIG[:host] || '127.0.0.1'
|
162
213
|
@port = port || begin
|
163
214
|
port_str = ::DEBUGGER__::CONFIG[:port] || raise("Specify listening port by RUBY_DEBUG_PORT environment variable.")
|
164
215
|
if /\A\d+\z/ !~ port_str
|
@@ -207,6 +258,8 @@ module DEBUGGER__
|
|
207
258
|
Socket.unix_server_loop @sock_path do |sock, client|
|
208
259
|
@client_addr = client
|
209
260
|
yield sock
|
261
|
+
ensure
|
262
|
+
sock.close
|
210
263
|
end
|
211
264
|
end
|
212
265
|
end
|