ruby-debug-ide-docker 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES +75 -0
- data/ChangeLog.archive +1073 -0
- data/ChangeLog.md +594 -0
- data/Gemfile +28 -0
- data/MIT-LICENSE +24 -0
- data/Rakefile +42 -0
- data/bin/gdb_wrapper +96 -0
- data/bin/rdebug-ide +183 -0
- data/ext/mkrf_conf.rb +48 -0
- data/lib/ruby-debug-ide.rb +173 -0
- data/lib/ruby-debug-ide/attach/debugger_loader.rb +20 -0
- data/lib/ruby-debug-ide/attach/gdb.rb +73 -0
- data/lib/ruby-debug-ide/attach/lldb.rb +71 -0
- data/lib/ruby-debug-ide/attach/native_debugger.rb +133 -0
- data/lib/ruby-debug-ide/attach/process_thread.rb +54 -0
- data/lib/ruby-debug-ide/attach/util.rb +115 -0
- data/lib/ruby-debug-ide/command.rb +177 -0
- data/lib/ruby-debug-ide/commands/breakpoints.rb +128 -0
- data/lib/ruby-debug-ide/commands/catchpoint.rb +64 -0
- data/lib/ruby-debug-ide/commands/condition.rb +51 -0
- data/lib/ruby-debug-ide/commands/control.rb +158 -0
- data/lib/ruby-debug-ide/commands/enable.rb +203 -0
- data/lib/ruby-debug-ide/commands/eval.rb +64 -0
- data/lib/ruby-debug-ide/commands/expression_info.rb +71 -0
- data/lib/ruby-debug-ide/commands/file_filtering.rb +107 -0
- data/lib/ruby-debug-ide/commands/frame.rb +155 -0
- data/lib/ruby-debug-ide/commands/inspect.rb +25 -0
- data/lib/ruby-debug-ide/commands/jump.rb +73 -0
- data/lib/ruby-debug-ide/commands/load.rb +18 -0
- data/lib/ruby-debug-ide/commands/pause.rb +33 -0
- data/lib/ruby-debug-ide/commands/set_type.rb +47 -0
- data/lib/ruby-debug-ide/commands/stepping.rb +108 -0
- data/lib/ruby-debug-ide/commands/threads.rb +178 -0
- data/lib/ruby-debug-ide/commands/variables.rb +154 -0
- data/lib/ruby-debug-ide/event_processor.rb +71 -0
- data/lib/ruby-debug-ide/greeter.rb +40 -0
- data/lib/ruby-debug-ide/helper.rb +33 -0
- data/lib/ruby-debug-ide/ide_processor.rb +155 -0
- data/lib/ruby-debug-ide/interface.rb +45 -0
- data/lib/ruby-debug-ide/multiprocess.rb +23 -0
- data/lib/ruby-debug-ide/multiprocess/monkey.rb +47 -0
- data/lib/ruby-debug-ide/multiprocess/pre_child.rb +67 -0
- data/lib/ruby-debug-ide/multiprocess/starter.rb +11 -0
- data/lib/ruby-debug-ide/multiprocess/unmonkey.rb +31 -0
- data/lib/ruby-debug-ide/version.rb +3 -0
- data/lib/ruby-debug-ide/xml_printer.rb +545 -0
- data/ruby-debug-ide-docker.gemspec +51 -0
- metadata +110 -0
@@ -0,0 +1,177 @@
|
|
1
|
+
if RUBY_VERSION < '2.0' || defined?(JRUBY_VERSION)
|
2
|
+
require 'ruby-debug-base'
|
3
|
+
else
|
4
|
+
require 'debase'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'ruby-debug-ide/helper'
|
8
|
+
require 'delegate'
|
9
|
+
|
10
|
+
module Debugger
|
11
|
+
|
12
|
+
class Command < SimpleDelegator # :nodoc:
|
13
|
+
SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
|
14
|
+
defined?(SubcmdStruct)
|
15
|
+
|
16
|
+
# Find param in subcmds. param id downcased and can be abbreviated
|
17
|
+
# to the minimum length listed in the subcommands
|
18
|
+
def find(subcmds, param)
|
19
|
+
param.downcase!
|
20
|
+
for try_subcmd in subcmds do
|
21
|
+
if (param.size >= try_subcmd.min) and
|
22
|
+
(try_subcmd.name[0..param.size-1] == param)
|
23
|
+
return try_subcmd
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def commands
|
31
|
+
@commands ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
DEF_OPTIONS = {
|
35
|
+
:event => true,
|
36
|
+
:control => false,
|
37
|
+
:unknown => false,
|
38
|
+
:need_context => false,
|
39
|
+
}
|
40
|
+
|
41
|
+
def inherited(klass)
|
42
|
+
DEF_OPTIONS.each do |o, v|
|
43
|
+
klass.options[o] = v if klass.options[o].nil?
|
44
|
+
end
|
45
|
+
commands << klass
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_commands
|
49
|
+
dir = File.dirname(__FILE__)
|
50
|
+
Dir[File.join(dir, 'commands', '*')].each do |file|
|
51
|
+
require file if file =~ /\.rb$/
|
52
|
+
end
|
53
|
+
Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
|
54
|
+
include mod
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(meth, *args, &block)
|
59
|
+
if meth.to_s =~ /^(.+?)=$/
|
60
|
+
@options[$1.intern] = args.first
|
61
|
+
else
|
62
|
+
if @options.has_key?(meth)
|
63
|
+
@options[meth]
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def options
|
71
|
+
@options ||= {}
|
72
|
+
end
|
73
|
+
|
74
|
+
def unescape_incoming(str)
|
75
|
+
str.gsub(/((?:^|[^\\])(?:\\\\)*)((?:\\n)+)/) do |_|
|
76
|
+
$1 + "\n" * ($2.size / 2)
|
77
|
+
end.gsub(/\\\\/, '\\')
|
78
|
+
end
|
79
|
+
|
80
|
+
def file_filter_supported?
|
81
|
+
defined?(Debugger.file_filter)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(state, printer)
|
86
|
+
@state, @printer = state, printer
|
87
|
+
super @printer
|
88
|
+
end
|
89
|
+
|
90
|
+
def match(input)
|
91
|
+
@match = regexp.match(input)
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def errmsg(*args)
|
97
|
+
@printer.print_error(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
def print(*args)
|
101
|
+
@state.print(*args)
|
102
|
+
end
|
103
|
+
|
104
|
+
# see Timeout::timeout, the difference is that we must use a DebugThread
|
105
|
+
# because every other thread would be halted when the event hook is reached
|
106
|
+
# in ruby-debug.c
|
107
|
+
def timeout(sec)
|
108
|
+
return yield if sec == nil or sec.zero?
|
109
|
+
if Thread.respond_to?(:critical) and Thread.critical
|
110
|
+
raise ThreadError, "timeout within critical session"
|
111
|
+
end
|
112
|
+
begin
|
113
|
+
x = Thread.current
|
114
|
+
y = DebugThread.start {
|
115
|
+
sleep sec
|
116
|
+
x.raise StandardError, "Timeout: evaluation took longer than #{sec} seconds." if x.alive?
|
117
|
+
}
|
118
|
+
yield sec
|
119
|
+
ensure
|
120
|
+
y.kill if y and y.alive?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def debug_eval(str, b = get_binding)
|
125
|
+
begin
|
126
|
+
str = str.to_s
|
127
|
+
str.force_encoding('UTF-8') if(RUBY_VERSION >= '2.0')
|
128
|
+
to_inspect = Command.unescape_incoming(str)
|
129
|
+
max_time = Debugger.evaluation_timeout
|
130
|
+
@printer.print_debug("Evaluating %s with timeout after %i sec", str, max_time)
|
131
|
+
timeout(max_time) do
|
132
|
+
eval(to_inspect, b)
|
133
|
+
end
|
134
|
+
rescue StandardError, ScriptError => e
|
135
|
+
@printer.print_exception(e, @state.binding)
|
136
|
+
throw :debug_error
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def debug_silent_eval(str)
|
141
|
+
begin
|
142
|
+
str = str.to_s
|
143
|
+
eval(str, get_binding)
|
144
|
+
rescue StandardError, ScriptError
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def get_binding
|
150
|
+
@state.context.frame_binding(@state.frame_pos)
|
151
|
+
end
|
152
|
+
|
153
|
+
def line_at(file, line)
|
154
|
+
Debugger.line_at(file, line)
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_context(thnum)
|
158
|
+
Debugger.contexts.find{|c| c.thnum == thnum}
|
159
|
+
end
|
160
|
+
|
161
|
+
def realpath(filename)
|
162
|
+
is_dir = filename.end_with?(File::SEPARATOR)
|
163
|
+
if filename.index(File::SEPARATOR) || File::ALT_SEPARATOR && filename.index(File::ALT_SEPARATOR)
|
164
|
+
filename = File.expand_path(filename)
|
165
|
+
end
|
166
|
+
if (RUBY_VERSION < '1.9') || (RbConfig::CONFIG['host_os'] =~ /mswin/)
|
167
|
+
filename
|
168
|
+
else
|
169
|
+
filename = File.realpath(filename) rescue filename
|
170
|
+
filename = filename + File::SEPARATOR if is_dir && !filename.end_with?(File::SEPARATOR)
|
171
|
+
filename
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
Command.load_commands
|
177
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Debugger
|
2
|
+
class AddBreakpoint < Command # :nodoc:
|
3
|
+
self.control = true
|
4
|
+
|
5
|
+
def regexp
|
6
|
+
/ ^\s*
|
7
|
+
b(?:reak)?
|
8
|
+
(?: \s+
|
9
|
+
(?:
|
10
|
+
(\d+) |
|
11
|
+
(.+?)[:.#]([^.:\s]+)
|
12
|
+
))?
|
13
|
+
(?:\s+
|
14
|
+
if\s+(.+)
|
15
|
+
)?
|
16
|
+
$
|
17
|
+
/x
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
if @match[1]
|
22
|
+
line, _, _, expr = @match.captures
|
23
|
+
else
|
24
|
+
_, file, line, expr = @match.captures
|
25
|
+
end
|
26
|
+
|
27
|
+
if file.nil?
|
28
|
+
file = File.basename(@state.file)
|
29
|
+
else
|
30
|
+
if line !~ /^\d+$/
|
31
|
+
klass = debug_silent_eval(file)
|
32
|
+
if klass && !klass.kind_of?(Module)
|
33
|
+
print_error "Unknown class #{file}"
|
34
|
+
throw :debug_error
|
35
|
+
end
|
36
|
+
file = klass.name if klass
|
37
|
+
else
|
38
|
+
file = realpath(file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if line =~ /^\d+$/
|
43
|
+
line = line.to_i
|
44
|
+
else
|
45
|
+
line = line.intern.id2name
|
46
|
+
end
|
47
|
+
|
48
|
+
b = Debugger.add_breakpoint file, line, expr
|
49
|
+
print_breakpoint_added b
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
def help_command
|
54
|
+
'break'
|
55
|
+
end
|
56
|
+
|
57
|
+
def help(cmd)
|
58
|
+
%{
|
59
|
+
b[reak] file:line [if expr]
|
60
|
+
b[reak] [file|class(:|.|#)]<line|method> [if expr] -
|
61
|
+
\tset breakpoint to some position, (optionally) if expr == true
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class BreakpointsCommand < Command # :nodoc:
|
68
|
+
self.control = true
|
69
|
+
|
70
|
+
def regexp
|
71
|
+
/^\s*info\s*break$/
|
72
|
+
end
|
73
|
+
|
74
|
+
def execute
|
75
|
+
print_breakpoints Debugger.breakpoints
|
76
|
+
end
|
77
|
+
|
78
|
+
class << self
|
79
|
+
def help_command
|
80
|
+
'break'
|
81
|
+
end
|
82
|
+
|
83
|
+
def help(cmd)
|
84
|
+
%{
|
85
|
+
b[reak]\tlist breakpoints
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class DeleteBreakpointCommand < Command # :nodoc:
|
92
|
+
self.control = true
|
93
|
+
|
94
|
+
def regexp
|
95
|
+
/^\s*del(?:ete)?(?:\s+(.*))?$/
|
96
|
+
end
|
97
|
+
|
98
|
+
def execute
|
99
|
+
brkpts = @match[1]
|
100
|
+
unless brkpts
|
101
|
+
Debugger.breakpoints.clear
|
102
|
+
else
|
103
|
+
brkpts.split(/[ \t]+/).each do |pos|
|
104
|
+
pos = get_int(pos, "Delete", 1)
|
105
|
+
return unless pos
|
106
|
+
b = Debugger.remove_breakpoint(pos)
|
107
|
+
if b
|
108
|
+
print_breakpoint_deleted b
|
109
|
+
else
|
110
|
+
print_error "No breakpoint number %d\n", pos
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class << self
|
117
|
+
def help_command
|
118
|
+
'delete'
|
119
|
+
end
|
120
|
+
|
121
|
+
def help(cmd)
|
122
|
+
%{
|
123
|
+
del[ete][ nnn...]\tdelete some or all breakpoints
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Debugger
|
2
|
+
class CatchCommand < Command # :nodoc:
|
3
|
+
self.control = true
|
4
|
+
|
5
|
+
def regexp
|
6
|
+
/^\s* cat(?:ch)?
|
7
|
+
(?:\s+ (\S+))?
|
8
|
+
(?:\s+ (off))? \s* $/ix
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
excn = @match[1]
|
13
|
+
if not excn
|
14
|
+
# No args given.
|
15
|
+
errmsg "Exception class must be specified for 'catch' command"
|
16
|
+
elsif not @match[2]
|
17
|
+
# One arg given.
|
18
|
+
if 'off' == excn
|
19
|
+
clear_catchpoints
|
20
|
+
else
|
21
|
+
Debugger.add_catchpoint(excn)
|
22
|
+
print_catchpoint_set(excn)
|
23
|
+
end
|
24
|
+
elsif @match[2] != 'off'
|
25
|
+
errmsg "Off expected. Got %s\n", @match[2]
|
26
|
+
elsif remove_catchpoint(excn)
|
27
|
+
print_catchpoint_deleted(excn)
|
28
|
+
else
|
29
|
+
errmsg "Catch for exception %s not found.\n", excn
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def help_command
|
35
|
+
'catch'
|
36
|
+
end
|
37
|
+
|
38
|
+
def help(cmd)
|
39
|
+
%{
|
40
|
+
cat[ch]\t\t\tshow catchpoint
|
41
|
+
cat[ch] off \tremove all catch points
|
42
|
+
cat[ch] <an Exception>\tset catchpoint to an exception
|
43
|
+
cat[ch] <an Exception> off \tremove catchpoint for an exception
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def clear_catchpoints
|
51
|
+
if Debugger.respond_to?(:clear_catchpoints)
|
52
|
+
Debugger.clear_catchpoints
|
53
|
+
else
|
54
|
+
Debugger.catchpoints.clear
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_catchpoint(excn)
|
59
|
+
return Debugger.remove_catchpoint(excn) if Debugger.respond_to?(:remove_catchpoint)
|
60
|
+
return Debugger.catchpoints.delete(excn) if Debugger.catchpoints.member?(excn)
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Debugger
|
2
|
+
|
3
|
+
class ConditionCommand < Command # :nodoc:
|
4
|
+
self.control = true
|
5
|
+
|
6
|
+
def regexp
|
7
|
+
/^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute
|
11
|
+
if not @match[1]
|
12
|
+
errmsg "\"condition\" must be followed a breakpoint number and expression\n"
|
13
|
+
else
|
14
|
+
breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
|
15
|
+
largest = breakpoints.inject(0) do |largest_so_far, b|
|
16
|
+
b.id if b.id > largest_so_far
|
17
|
+
end
|
18
|
+
if 0 == largest
|
19
|
+
print "No breakpoints have been set.\n"
|
20
|
+
return
|
21
|
+
end
|
22
|
+
pos = get_int(@match[1], "Condition", 1, largest)
|
23
|
+
return unless pos
|
24
|
+
breakpoints.each do |b|
|
25
|
+
if b.id == pos
|
26
|
+
b.expr = @match[2].empty? ? nil : @match[2]
|
27
|
+
print_contdition_set(b.id)
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def help_command
|
37
|
+
'condition'
|
38
|
+
end
|
39
|
+
|
40
|
+
def help(cmd)
|
41
|
+
%{
|
42
|
+
Condition breakpoint-number expression
|
43
|
+
Specify breakpoint number N to break only if COND is true.
|
44
|
+
N is an integer and COND is an expression to be evaluated whenever
|
45
|
+
breakpoint N is reached. If the empty string is used, the condition is removed.
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end # module Debugger
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Debugger
|
2
|
+
class QuitCommand < Command # :nodoc:
|
3
|
+
self.control = true
|
4
|
+
|
5
|
+
def regexp
|
6
|
+
/^\s*(?:q(?:uit)?|exit)\s*$/
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
begin
|
11
|
+
@printer.print_msg("finished")
|
12
|
+
@printer.print_debug("Exiting debugger.")
|
13
|
+
ensure
|
14
|
+
exit! # exit -> exit!: No graceful way to stop threads...
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def help_command
|
20
|
+
%w[quit exit]
|
21
|
+
end
|
22
|
+
|
23
|
+
def help(cmd)
|
24
|
+
%{
|
25
|
+
q[uit]\texit from debugger,
|
26
|
+
exit\talias to quit
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class RestartCommand < Command # :nodoc:
|
33
|
+
self.control = true
|
34
|
+
|
35
|
+
def regexp
|
36
|
+
/ ^\s*
|
37
|
+
(restart|R)
|
38
|
+
(\s+ \S+ .*)?
|
39
|
+
$
|
40
|
+
/x
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute
|
44
|
+
if not defined? Debugger::RDEBUG_SCRIPT or not defined? Debugger::ARGV
|
45
|
+
print "We are not in a context we can restart from.\n"
|
46
|
+
return
|
47
|
+
end
|
48
|
+
if @match[2]
|
49
|
+
args = Debugger::PROG_SCRIPT + " " + @match[2]
|
50
|
+
else
|
51
|
+
args = Debugger::ARGV.join(" ")
|
52
|
+
end
|
53
|
+
|
54
|
+
# An execv would be preferable to the "exec" below.
|
55
|
+
cmd = Debugger::RDEBUG_SCRIPT + " " + args
|
56
|
+
print "Re exec'ing:\n\t#{cmd}\n"
|
57
|
+
exec cmd
|
58
|
+
end
|
59
|
+
|
60
|
+
class << self
|
61
|
+
def help_command
|
62
|
+
'restart'
|
63
|
+
end
|
64
|
+
|
65
|
+
def help(cmd)
|
66
|
+
%{
|
67
|
+
restart|R [args]
|
68
|
+
Restart the program. This is is a re-exec - all debugger state
|
69
|
+
is lost. If command arguments are passed those are used.
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class StartCommand < Command # :nodoc:
|
76
|
+
self.control = true
|
77
|
+
|
78
|
+
def regexp
|
79
|
+
/^\s*(start)(\s+ \S+ .*)?$/x
|
80
|
+
end
|
81
|
+
|
82
|
+
def execute
|
83
|
+
@printer.print_debug("Starting: running program script")
|
84
|
+
Debugger.run_prog_script #Debugger.prog_script_running?
|
85
|
+
end
|
86
|
+
|
87
|
+
class << self
|
88
|
+
def help_command
|
89
|
+
'start'
|
90
|
+
end
|
91
|
+
|
92
|
+
def help(cmd)
|
93
|
+
%{
|
94
|
+
run prog script
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
class InterruptCommand < Command # :nodoc:
|
102
|
+
self.event = false
|
103
|
+
self.control = true
|
104
|
+
self.need_context = true
|
105
|
+
|
106
|
+
def regexp
|
107
|
+
/^\s*i(?:nterrupt)?\s*$/
|
108
|
+
end
|
109
|
+
|
110
|
+
def execute
|
111
|
+
unless Debugger.interrupt_last
|
112
|
+
context = Debugger.thread_context(Thread.main)
|
113
|
+
context.interrupt
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class << self
|
118
|
+
def help_command
|
119
|
+
'interrupt'
|
120
|
+
end
|
121
|
+
|
122
|
+
def help(cmd)
|
123
|
+
%{
|
124
|
+
i[nterrupt]\tinterrupt the program
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
class DetachCommand < Command # :nodoc:
|
132
|
+
self.control = true
|
133
|
+
|
134
|
+
def regexp
|
135
|
+
/^\s*detach\s*$/
|
136
|
+
end
|
137
|
+
|
138
|
+
def execute
|
139
|
+
Debugger.stop
|
140
|
+
Debugger.interface.close
|
141
|
+
Debugger::MultiProcess.undo_monkey
|
142
|
+
Debugger.control_thread = nil
|
143
|
+
Thread.current.exit #@control_thread is a current thread
|
144
|
+
end
|
145
|
+
|
146
|
+
class << self
|
147
|
+
def help_command
|
148
|
+
'detach'
|
149
|
+
end
|
150
|
+
|
151
|
+
def help(cmd)
|
152
|
+
%{
|
153
|
+
detach\ndetach debugger\nnote: this option is only for remote debugging (or local attach)
|
154
|
+
}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|