debugger-ide 0.0.1 → 0.0.2
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.
- data/Gemfile +4 -0
- data/MIT-LICENSE +24 -0
- data/Rakefile +108 -0
- data/lib/ruby-debug-ide.rb +184 -0
- data/lib/ruby-debug/command.rb +173 -0
- data/lib/ruby-debug/commands/breakpoints.rb +129 -0
- data/lib/ruby-debug/commands/catchpoint.rb +52 -0
- data/lib/ruby-debug/commands/condition.rb +51 -0
- data/lib/ruby-debug/commands/control.rb +129 -0
- data/lib/ruby-debug/commands/enable.rb +203 -0
- data/lib/ruby-debug/commands/eval.rb +64 -0
- data/lib/ruby-debug/commands/frame.rb +155 -0
- data/lib/ruby-debug/commands/inspect.rb +24 -0
- data/lib/ruby-debug/commands/jump.rb +73 -0
- data/lib/ruby-debug/commands/load.rb +18 -0
- data/lib/ruby-debug/commands/pause.rb +32 -0
- data/lib/ruby-debug/commands/set_type.rb +47 -0
- data/lib/ruby-debug/commands/stepping.rb +108 -0
- data/lib/ruby-debug/commands/threads.rb +153 -0
- data/lib/ruby-debug/commands/variables.rb +142 -0
- data/lib/ruby-debug/event_processor.rb +74 -0
- data/lib/ruby-debug/helper.rb +33 -0
- data/lib/ruby-debug/interface.rb +39 -0
- data/lib/ruby-debug/printers.rb +2 -0
- data/lib/ruby-debug/processor.rb +152 -0
- data/lib/ruby-debug/xml_printer.rb +268 -0
- metadata +28 -2
@@ -0,0 +1,153 @@
|
|
1
|
+
module Debugger
|
2
|
+
class ThreadListCommand < Command # :nodoc:
|
3
|
+
self.control = true
|
4
|
+
def regexp
|
5
|
+
/^\s*th(?:read)?\s+l(?:ist)?\s*$/
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute
|
9
|
+
contexts = Debugger.contexts.sort_by{|c| c.thnum}
|
10
|
+
print_contexts(contexts)
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def help_command
|
15
|
+
'thread'
|
16
|
+
end
|
17
|
+
|
18
|
+
def help(cmd)
|
19
|
+
%{
|
20
|
+
th[read] l[ist]\t\t\tlist all threads
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ThreadSwitchCommand < Command # :nodoc:
|
27
|
+
self.control = true
|
28
|
+
self.need_context = true
|
29
|
+
|
30
|
+
def regexp
|
31
|
+
/^\s*th(?:read)?\s+(?:sw(?:itch)?\s+)?(\d+)\s*$/
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute
|
35
|
+
c = get_context(@match[1].to_i)
|
36
|
+
case
|
37
|
+
when c == @state.context
|
38
|
+
print_msg "It's the current thread."
|
39
|
+
when c.ignored?
|
40
|
+
print_msg "Can't switch to the debugger thread."
|
41
|
+
else
|
42
|
+
print_context(c)
|
43
|
+
c.stop_next = 1
|
44
|
+
c.thread.run
|
45
|
+
@state.proceed
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
def help_command
|
51
|
+
'thread'
|
52
|
+
end
|
53
|
+
|
54
|
+
def help(cmd)
|
55
|
+
%{
|
56
|
+
th[read] [sw[itch]] <nnn>\tswitch thread context to nnn
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class ThreadStopCommand < Command # :nodoc:
|
63
|
+
self.control = true
|
64
|
+
self.need_context = true
|
65
|
+
|
66
|
+
def regexp
|
67
|
+
/^\s*th(?:read)?\s+stop\s+(\d+)\s*$/
|
68
|
+
end
|
69
|
+
|
70
|
+
def execute
|
71
|
+
c = get_context(@match[1].to_i)
|
72
|
+
case
|
73
|
+
when c == @state.context
|
74
|
+
print_msg "It's the current thread."
|
75
|
+
when c.ignored?
|
76
|
+
print_msg "Can't stop the debugger thread."
|
77
|
+
else
|
78
|
+
c.suspend
|
79
|
+
print_context(c)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class << self
|
84
|
+
def help_command
|
85
|
+
'thread'
|
86
|
+
end
|
87
|
+
|
88
|
+
def help(cmd)
|
89
|
+
%{
|
90
|
+
th[read] stop <nnn>\t\tstop thread nnn
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ThreadCurrentCommand < Command # :nodoc:
|
97
|
+
self.need_context = true
|
98
|
+
|
99
|
+
def regexp
|
100
|
+
/^\s*th(?:read)?\s+c(?:ur(?:rent)?)?\s*$/
|
101
|
+
end
|
102
|
+
|
103
|
+
def execute
|
104
|
+
print_context(@state.context)
|
105
|
+
end
|
106
|
+
|
107
|
+
class << self
|
108
|
+
def help_command
|
109
|
+
'thread'
|
110
|
+
end
|
111
|
+
|
112
|
+
def help(cmd)
|
113
|
+
%{
|
114
|
+
th[read] c[ur[rent]]\t\tshow current thread
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class ThreadResumeCommand < Command # :nodoc:
|
121
|
+
self.control = true
|
122
|
+
self.need_context = true
|
123
|
+
|
124
|
+
def regexp
|
125
|
+
/^\s*th(?:read)?\s+resume\s+(\d+)\s*$/
|
126
|
+
end
|
127
|
+
|
128
|
+
def execute
|
129
|
+
c = get_context(@match[1].to_i)
|
130
|
+
case
|
131
|
+
when c == @state.context
|
132
|
+
print_msg "It's the current thread."
|
133
|
+
when c.ignored?
|
134
|
+
print_msg "Can't resume the debugger thread."
|
135
|
+
else
|
136
|
+
c.resume
|
137
|
+
print_context(c)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class << self
|
142
|
+
def help_command
|
143
|
+
'thread'
|
144
|
+
end
|
145
|
+
|
146
|
+
def help(cmd)
|
147
|
+
%{
|
148
|
+
th[read] resume <nnn>\t\tresume thread nnn
|
149
|
+
}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Debugger
|
2
|
+
class VarConstantCommand < Command # :nodoc:
|
3
|
+
def regexp
|
4
|
+
/^\s*v(?:ar)?\s+c(?:onst(?:ant)?)?\s+/
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute
|
8
|
+
obj = debug_eval(@match.post_match)
|
9
|
+
unless obj.kind_of? Module
|
10
|
+
print_msg "Should be Class/Module: %s", @match.post_match
|
11
|
+
else
|
12
|
+
print_variables(obj.constants, "constant") do |var|
|
13
|
+
obj.const_get(var)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def help_command
|
20
|
+
'var'
|
21
|
+
end
|
22
|
+
|
23
|
+
def help(cmd)
|
24
|
+
%{
|
25
|
+
v[ar] c[onst] <object>\t\tshow constants of object
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class VarGlobalCommand < Command # :nodoc:
|
32
|
+
def regexp
|
33
|
+
/^\s*v(?:ar)?\s+g(?:lobal)?\s*$/
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute
|
37
|
+
globals = []
|
38
|
+
if RUBY_VERSION < "1.9"
|
39
|
+
globals = global_variables
|
40
|
+
else
|
41
|
+
Debugger::without_stderr { globals = global_variables - [:$KCODE, :$=] }
|
42
|
+
end
|
43
|
+
print_variables(globals, 'global') do |var|
|
44
|
+
debug_eval(var)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def help_command
|
50
|
+
'var'
|
51
|
+
end
|
52
|
+
|
53
|
+
def help(cmd)
|
54
|
+
%{
|
55
|
+
v[ar] g[lobal]\t\t\tshow global variables
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class VarInstanceCommand < Command # :nodoc:
|
62
|
+
def regexp
|
63
|
+
# id will be read as first match, name as post match
|
64
|
+
/^\s*v(?:ar)?\s+i(?:nstance)?\s+((?:[\\+-]0x)[\dabcdef]+)?/
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute
|
68
|
+
if (@match[1])
|
69
|
+
obj = ObjectSpace._id2ref(@match[1].hex) rescue nil
|
70
|
+
unless obj
|
71
|
+
# TODO: ensure that empty variables frame will be printed
|
72
|
+
@printer.print_msg("Unknown object id : %s", @match[1])
|
73
|
+
end
|
74
|
+
else
|
75
|
+
obj = debug_eval(@match.post_match)
|
76
|
+
end
|
77
|
+
return unless obj
|
78
|
+
if (obj.is_a?(Array)) then
|
79
|
+
print_array(obj)
|
80
|
+
elsif (obj.is_a?(Hash)) then
|
81
|
+
print_hash(obj)
|
82
|
+
else
|
83
|
+
print_element("variables") do
|
84
|
+
# instance variables
|
85
|
+
kind = 'instance'
|
86
|
+
inst_vars = obj.instance_variables
|
87
|
+
instance_binding = obj.instance_eval{binding()}
|
88
|
+
# print self at top position
|
89
|
+
print_variable('self', debug_eval('self', instance_binding), kind) if inst_vars.include?('self')
|
90
|
+
inst_vars.sort.each do |var|
|
91
|
+
print_variable(var, debug_eval(var, instance_binding), kind) unless var == 'self'
|
92
|
+
end
|
93
|
+
|
94
|
+
# class variables
|
95
|
+
class_binding = obj.class.class_eval('binding()')
|
96
|
+
obj.class.class_variables.sort.each do |var|
|
97
|
+
print_variable(var, debug_eval(var, class_binding), 'class')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
def help_command
|
105
|
+
'var'
|
106
|
+
end
|
107
|
+
|
108
|
+
def help(cmd)
|
109
|
+
%{
|
110
|
+
v[ar] i[nstance] <object>\tshow instance variables of object, object can be given by its id or an expression
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class VarLocalCommand < Command # :nodoc:
|
117
|
+
def regexp
|
118
|
+
/^\s*v(?:ar)?\s+l(?:ocal)?\s*$/
|
119
|
+
end
|
120
|
+
|
121
|
+
def execute
|
122
|
+
locals = @state.context.frame_locals(@state.frame_pos)
|
123
|
+
_self = @state.context.frame_self(@state.frame_pos)
|
124
|
+
locals['self'] = _self unless _self.to_s == "main"
|
125
|
+
print_variables(locals.keys, 'local') do |var|
|
126
|
+
locals[var]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class << self
|
131
|
+
def help_command
|
132
|
+
'var'
|
133
|
+
end
|
134
|
+
|
135
|
+
def help(cmd)
|
136
|
+
%{
|
137
|
+
v[ar] l[ocal]\t\t\tshow local variables
|
138
|
+
}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
if RUBY_VERSION < "1.9"
|
2
|
+
require 'ruby-debug/xml_printer'
|
3
|
+
else
|
4
|
+
require_relative 'xml_printer'
|
5
|
+
end
|
6
|
+
module Debugger
|
7
|
+
|
8
|
+
class EventProcessor
|
9
|
+
|
10
|
+
attr_accessor :line, :file, :context
|
11
|
+
|
12
|
+
def initialize(interface)
|
13
|
+
@printer = XmlPrinter.new(interface)
|
14
|
+
@line = nil
|
15
|
+
@file = nil
|
16
|
+
@last_breakpoint = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def at_breakpoint(context, breakpoint)
|
20
|
+
raise "@last_breakpoint supposed to be nil. is #{@last_breakpoint}" if @last_breakpoint
|
21
|
+
# at_breakpoint is immediately followed by #at_line event in
|
22
|
+
# ruby-debug-base. So postpone breakpoint printing until #at_line.
|
23
|
+
@last_breakpoint = breakpoint
|
24
|
+
end
|
25
|
+
|
26
|
+
def at_catchpoint(context, excpt)
|
27
|
+
@printer.print_catchpoint(excpt)
|
28
|
+
end
|
29
|
+
|
30
|
+
def at_tracing(context, file, line)
|
31
|
+
@printer.print_trace(context, file, line)
|
32
|
+
end
|
33
|
+
|
34
|
+
def at_line(context, file, line)
|
35
|
+
@printer.print_at_line(context, file, line) if context.nil? || context.stop_reason == :step
|
36
|
+
line_event(context, file, line)
|
37
|
+
end
|
38
|
+
|
39
|
+
def at_return(context, file, line)
|
40
|
+
@printer.print_at_line(context, file, line)
|
41
|
+
context.stop_frame = -1
|
42
|
+
line_event(context, file, line)
|
43
|
+
end
|
44
|
+
|
45
|
+
def line_event(context, file, line)
|
46
|
+
@line = line
|
47
|
+
@file = file
|
48
|
+
@context = context
|
49
|
+
if @last_breakpoint
|
50
|
+
# followed after #at_breakpoint in the same thread. Print breakpoint
|
51
|
+
# now when @line, @file and @context are correctly set to prevent race
|
52
|
+
# condition with `control thread'.
|
53
|
+
n = Debugger.breakpoints.index(@last_breakpoint) + 1
|
54
|
+
@printer.print_breakpoint n, @last_breakpoint
|
55
|
+
@last_breakpoint = nil
|
56
|
+
end
|
57
|
+
raise "DebuggerThread are not supposed to be traced (#{context.thread})" if context.thread.is_a?(Debugger::DebugThread)
|
58
|
+
@printer.print_debug("Stopping Thread %s", context.thread.to_s)
|
59
|
+
@printer.print_debug("Threads equal: %s", Thread.current == context.thread)
|
60
|
+
# will be resumed by commands like `step', `next', `continue', `finish'
|
61
|
+
# from `control thread'
|
62
|
+
Thread.stop
|
63
|
+
@printer.print_debug("Resumed Thread %s", context.thread.to_s)
|
64
|
+
@line = nil
|
65
|
+
@file = nil
|
66
|
+
@context = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def at_line?
|
70
|
+
@line
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Debugger
|
2
|
+
|
3
|
+
module ParseFunctions
|
4
|
+
# Parse 'str' of command 'cmd' as an integer between
|
5
|
+
# min and max. If either min or max is nil, that
|
6
|
+
# value has no bound.
|
7
|
+
def get_int(str, cmd, min=nil, max=nil, default=1)
|
8
|
+
return default unless str
|
9
|
+
begin
|
10
|
+
int = Integer(str)
|
11
|
+
if min and int < min
|
12
|
+
print_error "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
|
13
|
+
return nil
|
14
|
+
elsif max and int > max
|
15
|
+
print_error "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
return int
|
19
|
+
rescue
|
20
|
+
print_error "%s argument '%s' needs to be a number.\n" % [cmd, str]
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return true if code is syntactically correct for Ruby.
|
26
|
+
def syntax_valid?(code)
|
27
|
+
eval("BEGIN {return true}\n#{code}", nil, "", 0)
|
28
|
+
rescue Exception
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class TCPSocket
|
2
|
+
|
3
|
+
# Workaround for JRuby issue http://jira.codehaus.org/browse/JRUBY-2063
|
4
|
+
def non_blocking_gets
|
5
|
+
loop do
|
6
|
+
result, _, _ = IO.select( [self], nil, nil, 0.2 )
|
7
|
+
next unless result
|
8
|
+
return result[0].gets
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
module Debugger
|
15
|
+
|
16
|
+
class RemoteInterface # :nodoc:
|
17
|
+
|
18
|
+
def initialize(socket)
|
19
|
+
@socket = socket
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_command
|
23
|
+
result = @socket.non_blocking_gets
|
24
|
+
raise IOError unless result
|
25
|
+
result.chomp
|
26
|
+
end
|
27
|
+
|
28
|
+
def print(*args)
|
29
|
+
@socket.printf(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
@socket.close
|
34
|
+
rescue Exception
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|