ruby-debug 0.2-mswin32 → 0.3-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +22 -5
- data/Rakefile +1 -1
- data/bin/rdebug +16 -27
- data/ext/ruby_debug.c +20 -40
- data/lib/ruby-debug.rb +123 -45
- data/lib/ruby-debug/command.rb +76 -0
- data/lib/ruby-debug/commands/breakpoints.rb +136 -0
- data/lib/ruby-debug/commands/catchpoint.rb +40 -0
- data/lib/ruby-debug/commands/control.rb +55 -0
- data/lib/ruby-debug/commands/display.rb +106 -0
- data/lib/ruby-debug/commands/eval.rb +54 -0
- data/lib/ruby-debug/commands/frame.rb +125 -0
- data/lib/ruby-debug/commands/help.rb +47 -0
- data/lib/ruby-debug/commands/list.rb +67 -0
- data/lib/ruby-debug/commands/method.rb +53 -0
- data/lib/ruby-debug/commands/stepping.rb +104 -0
- data/lib/ruby-debug/commands/threads.rb +164 -0
- data/lib/ruby-debug/commands/tmate.rb +25 -0
- data/lib/ruby-debug/commands/trace.rb +33 -0
- data/lib/ruby-debug/commands/variables.rb +113 -0
- data/lib/ruby-debug/lock.rb +41 -0
- data/lib/ruby-debug/processor.rb +118 -555
- data/lib/ruby_debug.so +0 -0
- metadata +19 -3
- data/bin/remote +0 -30
@@ -0,0 +1,25 @@
|
|
1
|
+
module Debugger
|
2
|
+
if RUBY_PLATFORM =~ /darwin/
|
3
|
+
class TextMateCommand < Command
|
4
|
+
def regexp
|
5
|
+
/^\s*tm(?:ate)?$/
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute
|
9
|
+
%x|open 'txmt://open?url=file://#{File.expand_path(@state.file)}&line=#{@state.line}'|
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def help_command
|
14
|
+
'tmate'
|
15
|
+
end
|
16
|
+
|
17
|
+
def help(cmd)
|
18
|
+
%{
|
19
|
+
tm[ate]\topens a current file in TextMate
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Debugger
|
2
|
+
class TraceCommand < Command
|
3
|
+
def regexp
|
4
|
+
/^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute
|
8
|
+
if @match[2]
|
9
|
+
Debugger.tracing = @match[1] == 'on'
|
10
|
+
elsif @match[1]
|
11
|
+
@state.context.tracing = @match[1] == 'on'
|
12
|
+
end
|
13
|
+
if Debugger.tracing || @state.context.tracing
|
14
|
+
print "Trace on.\n"
|
15
|
+
else
|
16
|
+
print "Trace off.\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def help_command
|
22
|
+
'trace'
|
23
|
+
end
|
24
|
+
|
25
|
+
def help(cmd)
|
26
|
+
%{
|
27
|
+
tr[ace] (on|off)\tset trace mode of current thread
|
28
|
+
tr[ace] (on|off) all\tset trace mode of all threads
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Debugger
|
2
|
+
module VarFunctions
|
3
|
+
def var_list(ary, bind = nil)
|
4
|
+
bind ||= @state.binding
|
5
|
+
ary.sort!
|
6
|
+
for v in ary
|
7
|
+
print " %s => %s\n", v, eval(v, bind).inspect
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class VarConstantCommand < Command
|
13
|
+
include VarFunctions
|
14
|
+
|
15
|
+
def regexp
|
16
|
+
/^\s*v(?:ar)?\s+c(?:onst(?:ant)?)?\s+/
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute
|
20
|
+
obj = debug_eval(@match.post_match)
|
21
|
+
unless obj.kind_of? Module
|
22
|
+
print "Should be Class/Module: %s\n", @match.post_match
|
23
|
+
else
|
24
|
+
var_list(obj.constants, obj.module_eval{binding()})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def help_command
|
30
|
+
'var'
|
31
|
+
end
|
32
|
+
|
33
|
+
def help(cmd)
|
34
|
+
%{
|
35
|
+
v[ar] c[onst] <object>\t\tshow constants of object
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class VarGlobalCommand < Command
|
42
|
+
include VarFunctions
|
43
|
+
|
44
|
+
def regexp
|
45
|
+
/^\s*v(?:ar)?\s+g(?:lobal)?\s*$/
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute
|
49
|
+
var_list(global_variables)
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
def help_command
|
54
|
+
'var'
|
55
|
+
end
|
56
|
+
|
57
|
+
def help(cmd)
|
58
|
+
%{
|
59
|
+
v[ar] g[lobal]\t\t\tshow global variables
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class VarInstanceCommand < Command
|
66
|
+
include VarFunctions
|
67
|
+
|
68
|
+
def regexp
|
69
|
+
/^\s*v(?:ar)?\s+i(?:nstance)?\s+/
|
70
|
+
end
|
71
|
+
|
72
|
+
def execute
|
73
|
+
obj = debug_eval(@match.post_match)
|
74
|
+
var_list(obj.instance_variables, obj.instance_eval{binding()})
|
75
|
+
end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
def help_command
|
79
|
+
'var'
|
80
|
+
end
|
81
|
+
|
82
|
+
def help(cmd)
|
83
|
+
%{
|
84
|
+
v[ar] i[nstance] <object>\tshow instance variables of object
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class VarLocalCommand < Command
|
91
|
+
include VarFunctions
|
92
|
+
|
93
|
+
def regexp
|
94
|
+
/^\s*v(?:ar)?\s+l(?:ocal)?\s*$/
|
95
|
+
end
|
96
|
+
|
97
|
+
def execute
|
98
|
+
var_list(eval("local_variables", @state.binding))
|
99
|
+
end
|
100
|
+
|
101
|
+
class << self
|
102
|
+
def help_command
|
103
|
+
'var'
|
104
|
+
end
|
105
|
+
|
106
|
+
def help(cmd)
|
107
|
+
%{
|
108
|
+
v[ar] l[ocal]\t\t\tshow local variables
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Debugger
|
2
|
+
class Lock
|
3
|
+
def initialize
|
4
|
+
@locker = nil
|
5
|
+
@waiting = []
|
6
|
+
@locked = false;
|
7
|
+
end
|
8
|
+
|
9
|
+
def locked?
|
10
|
+
@locked
|
11
|
+
end
|
12
|
+
|
13
|
+
def lock
|
14
|
+
return if Thread.critical
|
15
|
+
return if @locker == Thread.current
|
16
|
+
while (Thread.critical = true; @locked)
|
17
|
+
@waiting.push Thread.current
|
18
|
+
Thread.stop
|
19
|
+
end
|
20
|
+
@locked = true
|
21
|
+
@locker = Thread.current
|
22
|
+
Thread.critical = false
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def unlock
|
27
|
+
return if Thread.critical
|
28
|
+
return unless @locked
|
29
|
+
unless @locker == Thread.current
|
30
|
+
raise RuntimeError, "unlocked by other"
|
31
|
+
end
|
32
|
+
Thread.critical = true
|
33
|
+
t = @waiting.shift
|
34
|
+
@locked = false
|
35
|
+
@locker = nil
|
36
|
+
Thread.critical = false
|
37
|
+
t.run if t
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/ruby-debug/processor.rb
CHANGED
@@ -1,66 +1,71 @@
|
|
1
1
|
require 'ruby-debug/interface'
|
2
|
+
require 'ruby-debug/command'
|
2
3
|
|
3
4
|
module Debugger
|
4
5
|
class CommandProcessor
|
5
|
-
DEBUG_LAST_CMD = []
|
6
|
-
|
7
6
|
attr_accessor :interface
|
7
|
+
attr_reader :display
|
8
8
|
|
9
9
|
def initialize(interface = LocalInterface.new)
|
10
10
|
@interface = interface
|
11
11
|
@display = []
|
12
12
|
@mutex = Mutex.new
|
13
|
+
@last_cmd = nil
|
13
14
|
end
|
14
15
|
|
15
16
|
def interface=(interface)
|
16
17
|
@mutex.synchronize do
|
17
|
-
@interface.close
|
18
|
-
@interface = interface
|
18
|
+
@interface.close if @interface
|
19
|
+
@interface = interface
|
19
20
|
end
|
20
21
|
end
|
21
|
-
|
22
|
+
|
23
|
+
def self.protect(mname)
|
24
|
+
alias_method "__#{mname}", mname
|
25
|
+
module_eval %{
|
26
|
+
def #{mname}(*args)
|
27
|
+
@mutex.synchronize do
|
28
|
+
return unless @interface
|
29
|
+
__#{mname}(*args)
|
30
|
+
end
|
31
|
+
rescue IOError
|
32
|
+
self.interface = nil
|
33
|
+
rescue Exception
|
34
|
+
print "INTERNAL ERROR!!! #\{$!\}\n"
|
35
|
+
print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n")
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
22
40
|
def at_breakpoint(context, breakpoint)
|
23
|
-
|
24
|
-
|
25
|
-
n = Debugger.breakpoints.index(breakpoint) + 1
|
26
|
-
print "Breakpoint %d at %s:%s\n", n, breakpoint.source, breakpoint.pos
|
27
|
-
end
|
28
|
-
rescue IOError
|
29
|
-
self.interface = nil
|
41
|
+
n = Debugger.breakpoints.index(breakpoint) + 1
|
42
|
+
print "Breakpoint %d at %s:%s\n", n, breakpoint.source, breakpoint.pos
|
30
43
|
end
|
44
|
+
protect :at_breakpoint
|
31
45
|
|
32
46
|
def at_catchpoint(context, excpt)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
print "\tfrom %s\n", i
|
41
|
-
end
|
47
|
+
frames = context.frames
|
48
|
+
print "Catchpoint at %s:%d: `%s' (%s)\n", frames[0].file, frames[0].line, excpt, excpt.class
|
49
|
+
fs = frames.size
|
50
|
+
tb = caller(0)[-fs..-1]
|
51
|
+
if tb
|
52
|
+
for i in tb
|
53
|
+
print "\tfrom %s\n", i
|
42
54
|
end
|
43
55
|
end
|
44
|
-
rescue IOError
|
45
|
-
self.interface = nil
|
46
56
|
end
|
57
|
+
protect :at_catchpoint
|
47
58
|
|
48
59
|
def at_tracing(context, file, line)
|
49
|
-
|
50
|
-
print "Tracing(%d):%s:%s %s", context.thnum, file, line, line_at(file, line)
|
51
|
-
end
|
52
|
-
rescue IOError
|
53
|
-
self.interface = nil
|
60
|
+
print "Tracing(%d):%s:%s %s", context.thnum, file, line, Debugger.line_at(file, line)
|
54
61
|
end
|
62
|
+
protect :at_tracing
|
55
63
|
|
56
|
-
def at_line(
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
rescue IOError
|
61
|
-
puts 'error'
|
62
|
-
self.interface = nil
|
64
|
+
def at_line(context, file, line, binding)
|
65
|
+
print "%s:%d: %s", file, line, Debugger.line_at(file, line)
|
66
|
+
process_commands(context, file, line, binding)
|
63
67
|
end
|
68
|
+
protect :at_line
|
64
69
|
|
65
70
|
private
|
66
71
|
|
@@ -69,559 +74,117 @@ module Debugger
|
|
69
74
|
end
|
70
75
|
|
71
76
|
def process_commands(context, file, line, binding)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
event_cmds = Command.commands.select{|cmd| cmd.event }
|
78
|
+
state = State.new do |s|
|
79
|
+
s.context = context
|
80
|
+
s.file = file
|
81
|
+
s.line = line
|
82
|
+
s.binding = binding
|
83
|
+
s.display = display
|
84
|
+
s.interface = interface
|
85
|
+
s.commands = event_cmds
|
86
|
+
end
|
87
|
+
commands = event_cmds.map{|cmd| cmd.new(state) }
|
88
|
+
commands.find{ |cmd| cmd.kind_of?(DisplayCommand) }.execute
|
89
|
+
|
90
|
+
while !state.proceed? and input = @interface.read_command("(rdb:%d) " % context.thnum)
|
80
91
|
catch(:debug_error) do
|
81
92
|
if input == ""
|
82
|
-
next unless
|
83
|
-
input =
|
93
|
+
next unless @last_cmd
|
94
|
+
input = @last_cmd
|
84
95
|
else
|
85
|
-
|
96
|
+
@last_cmd = input
|
86
97
|
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
context.stop_next = $1 ? $1.to_i : 1
|
91
|
-
prompt = false
|
92
|
-
|
93
|
-
when /^\s*c(?:ont)?$|^\s*r(?:un)?$/
|
94
|
-
prompt = false
|
95
|
-
|
96
|
-
when /^\s*v(?:ar)?\s+/
|
97
|
-
debug_variable_info($', binding)
|
98
|
-
|
99
|
-
when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/
|
100
|
-
display_frames(context, frame_pos)
|
101
|
-
|
102
|
-
when /^\s*l(?:ist)?(?:\s+(.+))?$/
|
103
|
-
if not $1
|
104
|
-
b = previous_line ? previous_line + 10 : binding_line - 5
|
105
|
-
e = b + 9
|
106
|
-
elsif $1 == '-'
|
107
|
-
b = previous_line ? previous_line - 10 : binding_line - 5
|
108
|
-
e = b + 9
|
109
|
-
else
|
110
|
-
b, e = $1.split(/[-,]/)
|
111
|
-
if e
|
112
|
-
b = b.to_i
|
113
|
-
e = e.to_i
|
114
|
-
else
|
115
|
-
b = b.to_i - 5
|
116
|
-
e = b + 9
|
117
|
-
end
|
118
|
-
end
|
119
|
-
previous_line = b
|
120
|
-
display_list(b, e, binding_file, binding_line)
|
121
|
-
|
122
|
-
when /^\s*n(?:ext)?(?:\s+(\d+))?$/
|
123
|
-
steps = $1 ? $1.to_i : 1
|
124
|
-
context.step_over steps, context.frames.size - frame_pos
|
125
|
-
prompt = false
|
126
|
-
|
127
|
-
when /^\s*up(?:\s+(\d+))?$/
|
128
|
-
previous_line = nil
|
129
|
-
frame_pos += $1 ? $1.to_i : 1
|
130
|
-
if frame_pos >= context.frames.size
|
131
|
-
frame_pos = context.frames.size - 1
|
132
|
-
print "At toplevel"
|
133
|
-
end
|
134
|
-
frame = context.frames[frame_pos]
|
135
|
-
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
136
|
-
print format_frame(frame, frame_pos)
|
137
|
-
|
138
|
-
when /^\s*down(?:\s+(\d+))?$/
|
139
|
-
previous_line = nil
|
140
|
-
frame_pos -= $1 ? $1.to_i : 1
|
141
|
-
if frame_pos < 0
|
142
|
-
frame_pos = 0
|
143
|
-
print "At stack bottom\n"
|
144
|
-
end
|
145
|
-
frame = context.frames[frame_pos]
|
146
|
-
binding, binding_file, binding_line = frame.binding, frame.file, frame.line
|
147
|
-
print format_frame(frame, frame_pos)
|
148
|
-
|
149
|
-
when /^\s*fin(?:ish)?$/
|
150
|
-
if frame_pos == context.frames.size
|
151
|
-
print "\"finish\" not meaningful in the outermost frame.\n"
|
152
|
-
else
|
153
|
-
context.stop_frame = context.frames.size - frame_pos
|
154
|
-
frame_pos = 0
|
155
|
-
prompt = false
|
156
|
-
end
|
157
|
-
|
158
|
-
when /^\s*b(?:reak)?\s+(?:(.+):)?([^.:\s]+)\s*(?:\sif\s+(.+))?$/
|
159
|
-
pos = $2
|
160
|
-
expr = $3
|
161
|
-
b_file = file
|
162
|
-
if $1
|
163
|
-
klass = debug_silent_eval($1, binding)
|
164
|
-
if klass && !klass.kind_of?(Module)
|
165
|
-
print "Unknown class #$1\n"
|
166
|
-
throw :debug_error
|
167
|
-
end
|
168
|
-
klass = klass.name if klass
|
169
|
-
b_file = $1
|
170
|
-
end
|
171
|
-
if pos =~ /^\d+$/
|
172
|
-
pname = pos
|
173
|
-
pos = pos.to_i
|
174
|
-
else
|
175
|
-
pname = pos = pos.intern.id2name
|
176
|
-
end
|
177
|
-
b_file = File.basename(b_file)
|
178
|
-
Debugger.add_breakpoint klass || b_file, pos, expr
|
179
|
-
print "Set breakpoint %d at %s:%s\n", Debugger.breakpoints.size, klass || b_file, pname
|
180
|
-
|
181
|
-
when /^\s*b(?:reak)?\s+(.+)[#.]([^.:\s]+)(?:\s+if\s+(.+))?$/
|
182
|
-
pos = $2.intern.id2name
|
183
|
-
expr = $3
|
184
|
-
klass = debug_eval($1, binding)
|
185
|
-
if klass.nil? || !klass.kind_of?(Module)
|
186
|
-
print "Unknown class #$1\n"
|
187
|
-
throw :debug_error
|
188
|
-
end
|
189
|
-
Debugger.add_breakpoint klass.name, pos, expr
|
190
|
-
print "Set breakpoint %d at %s.%s\n", Debugger.breakpoints.size, klass, pos
|
191
|
-
|
192
|
-
when /^\s*b(?:reak)?$/
|
193
|
-
unless Debugger.breakpoints.empty?
|
194
|
-
print "Breakpoints:\n"
|
195
|
-
Debugger.breakpoints.each_with_index do |b, n|
|
196
|
-
if b.expr.nil?
|
197
|
-
print " %d %s:%s\n", n+1, b.source, b.pos
|
198
|
-
else
|
199
|
-
print " %d %s:%s if %s\n", n+1, b.source, b.pos, b.expr
|
200
|
-
end
|
201
|
-
end
|
202
|
-
print "\n"
|
203
|
-
else
|
204
|
-
print "No breakpoints\n"
|
205
|
-
end
|
206
|
-
when /^\s*del(?:ete)?(?:\s+(\d+))?$/
|
207
|
-
pos = $1
|
208
|
-
unless pos
|
209
|
-
input = @interface.confirm("Clear all breakpoints? (y/n) ")
|
210
|
-
if input == "y"
|
211
|
-
Debugger.breakpoints.clear
|
212
|
-
end
|
213
|
-
else
|
214
|
-
pos = pos.to_i
|
215
|
-
unless Debugger.breakpoints.delete_at(pos-1)
|
216
|
-
print "Breakpoint %d is not defined\n", pos
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
when /^\s*th(?:read)?\s+/
|
221
|
-
if debug_thread_info($') == :cont
|
222
|
-
prompt = false
|
223
|
-
end
|
224
|
-
|
225
|
-
when /^\s*m(?:ethod)?\s+/
|
226
|
-
debug_method_info($', binding)
|
227
|
-
|
228
|
-
when /^\s*pp\s+/
|
229
|
-
out = StringIO.new
|
230
|
-
PP.pp(debug_eval($', binding), out) rescue out.puts $!.message
|
231
|
-
print out.string
|
232
|
-
|
233
|
-
when /^\s*(\s*p|e(?:val)?)\s+/
|
234
|
-
print "%s\n", debug_eval($', binding).inspect
|
235
|
-
|
236
|
-
when /^\s*h(?:elp)?(?:\s+(.+))?$/
|
237
|
-
debug_print_help($1)
|
238
|
-
|
239
|
-
when /^\s*q(?:uit)?$/
|
240
|
-
input = @interface.confirm("Really quit? (y/n) ")
|
241
|
-
if input == "y"
|
242
|
-
exit! # exit -> exit!: No graceful way to stop threads...
|
243
|
-
end
|
244
|
-
|
245
|
-
when /^\s*disp(?:lay)?\s+(.+)$/
|
246
|
-
exp = $1
|
247
|
-
@display.push [true, exp]
|
248
|
-
print "%d: ", @display.size
|
249
|
-
display_expression(exp, binding)
|
250
|
-
|
251
|
-
when /^\s*disp(?:lay)?$/
|
252
|
-
display_expressions(binding)
|
253
|
-
|
254
|
-
when /^\s*undisp(?:lay)?(?:\s+(\d+))?$/
|
255
|
-
pos = $1
|
256
|
-
unless pos
|
257
|
-
input = @interface.confirm("Clear all expressions? (y/n) ")
|
258
|
-
if input == "y"
|
259
|
-
for d in @display
|
260
|
-
d[0] = false
|
261
|
-
end
|
262
|
-
end
|
263
|
-
else
|
264
|
-
pos = pos.to_i
|
265
|
-
if @display[pos-1]
|
266
|
-
@display[pos-1][0] = false
|
267
|
-
else
|
268
|
-
print "Display expression %d is not defined\n", pos
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
when /^\s*cat(?:ch)?(?:\s+(.+))?$/
|
273
|
-
if $1
|
274
|
-
excn = $1
|
275
|
-
if excn == 'off'
|
276
|
-
Debugger.catchpoint = nil
|
277
|
-
print "Clear catchpoint.\n"
|
278
|
-
else
|
279
|
-
Debugger.catchpoint = excn
|
280
|
-
print "Set catchpoint %s.\n", excn
|
281
|
-
end
|
282
|
-
else
|
283
|
-
if Debugger.catchpoint
|
284
|
-
print "Catchpoint %s.\n", Debugger.catchpoint
|
285
|
-
else
|
286
|
-
print "No catchpoint.\n"
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/
|
291
|
-
if defined?( $2 )
|
292
|
-
Debugger.tracing = $1 == 'on'
|
293
|
-
elsif defined?( $1 )
|
294
|
-
context.tracing = $1 == 'on'
|
295
|
-
end
|
296
|
-
if Debugger.tracing || context.tracing
|
297
|
-
print "Trace on.\n"
|
298
|
-
else
|
299
|
-
print "Trace off.\n"
|
300
|
-
end
|
301
|
-
|
98
|
+
|
99
|
+
if cmd = commands.find{ |c| c.match(input) }
|
100
|
+
cmd.execute
|
302
101
|
else
|
303
102
|
print "Unknown command\n"
|
304
103
|
end
|
305
104
|
end
|
306
105
|
end
|
307
106
|
end
|
308
|
-
|
309
|
-
def display_expressions(binding)
|
310
|
-
n = 1
|
311
|
-
for d in @display
|
312
|
-
if d[0]
|
313
|
-
print "%d: ", n
|
314
|
-
display_expression(d[1], binding)
|
315
|
-
end
|
316
|
-
n += 1
|
317
|
-
end
|
318
|
-
end
|
319
107
|
|
320
|
-
|
321
|
-
|
322
|
-
|
108
|
+
class State
|
109
|
+
attr_accessor :context, :file, :line, :binding
|
110
|
+
attr_accessor :frame_pos, :previous_line, :display
|
111
|
+
attr_accessor :interface, :commands
|
323
112
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
at = eval("caller(1)", binding)
|
329
|
-
print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
|
330
|
-
for i in at
|
331
|
-
print "\tfrom %s\n", i
|
332
|
-
end
|
333
|
-
throw :debug_error
|
113
|
+
def initialize
|
114
|
+
@frame_pos = 0
|
115
|
+
@previous_line = nil
|
116
|
+
yield self
|
334
117
|
end
|
335
|
-
end
|
336
118
|
|
337
|
-
|
338
|
-
|
339
|
-
eval(str, binding)
|
340
|
-
rescue StandardError, ScriptError
|
341
|
-
nil
|
119
|
+
def print(*args)
|
120
|
+
@interface.print(*args)
|
342
121
|
end
|
343
|
-
end
|
344
|
-
|
345
|
-
def debug_variable_info(input, binding)
|
346
|
-
case input
|
347
|
-
when /^\s*g(?:lobal)?\s*$/
|
348
|
-
var_list(global_variables, binding)
|
349
|
-
|
350
|
-
when /^\s*l(?:ocal)?\s*$/
|
351
|
-
var_list(eval("local_variables", binding), binding)
|
352
|
-
|
353
|
-
when /^\s*i(?:nstance)?\s+/
|
354
|
-
obj = debug_eval($', binding)
|
355
|
-
var_list(obj.instance_variables, obj.instance_eval{binding()})
|
356
122
|
|
357
|
-
|
358
|
-
|
359
|
-
unless obj.kind_of? Module
|
360
|
-
print "Should be Class/Module: %s\n", $'
|
361
|
-
else
|
362
|
-
var_list(obj.constants, obj.module_eval{binding()})
|
363
|
-
end
|
123
|
+
def confirm(*args)
|
124
|
+
@interface.confirm(*args)
|
364
125
|
end
|
365
|
-
end
|
366
126
|
|
367
|
-
|
368
|
-
|
369
|
-
if idx == pos
|
370
|
-
print "--> "
|
371
|
-
else
|
372
|
-
print " "
|
373
|
-
end
|
374
|
-
print format_frame(frame, idx)
|
127
|
+
def proceed?
|
128
|
+
@proceed
|
375
129
|
end
|
376
|
-
end
|
377
|
-
|
378
|
-
def format_frame(frame, pos)
|
379
|
-
file, line, id = frame.file, frame.line, frame.id
|
380
|
-
"#%d %s:%s%s\n" % [pos + 1, file, line, (id ? ":in `#{id.id2name}'" : "")]
|
381
|
-
end
|
382
130
|
|
383
|
-
|
384
|
-
|
385
|
-
for v in ary
|
386
|
-
print " %s => %s\n", v, eval(v, binding).inspect
|
131
|
+
def proceed
|
132
|
+
@proceed = true
|
387
133
|
end
|
388
134
|
end
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
b.upto(e) do |n|
|
395
|
-
if n > 0 && lines[n-1]
|
396
|
-
if n == line
|
397
|
-
print "=> %d %s\n", n, lines[n-1].chomp
|
398
|
-
else
|
399
|
-
print " %d %s\n", n, lines[n-1].chomp
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
else
|
404
|
-
print "No sourcefile available for %s\n", file
|
405
|
-
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class ControlCommandProcessor
|
138
|
+
def initialize(interface)
|
139
|
+
@interface = interface
|
406
140
|
end
|
407
|
-
|
408
|
-
def
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
else
|
425
|
-
obj = debug_eval(input, binding)
|
426
|
-
unless obj.kind_of? Module
|
427
|
-
print "Should be Class/Module: %s\n", input
|
428
|
-
else
|
429
|
-
len = 0
|
430
|
-
for v in obj.instance_methods(false).sort
|
431
|
-
len += v.size + 1
|
432
|
-
if len > 70
|
433
|
-
len = v.size + 1
|
434
|
-
print "\n"
|
435
|
-
end
|
436
|
-
print "%s ", v
|
141
|
+
|
142
|
+
def print(*args)
|
143
|
+
@interface.print(*args)
|
144
|
+
end
|
145
|
+
|
146
|
+
def process_commands
|
147
|
+
control_cmds = Command.commands.select{|cmd| cmd.control }
|
148
|
+
state = State.new(@interface, control_cmds)
|
149
|
+
commands = control_cmds.map{|cmd| cmd.new(state) }
|
150
|
+
|
151
|
+
while input = @interface.read_command("(rdb:ctrl) ")
|
152
|
+
catch(:debug_error) do
|
153
|
+
if cmd = commands.find{|c| c.match(input) }
|
154
|
+
cmd.execute
|
155
|
+
else
|
156
|
+
print "Unknown command\n"
|
437
157
|
end
|
438
|
-
print "\n"
|
439
158
|
end
|
440
159
|
end
|
160
|
+
rescue IOError
|
161
|
+
rescue Exception
|
162
|
+
print "INTERNAL ERROR!!! #{$!}\n"
|
163
|
+
print $!.backtrace.map{|l| "\t#{l}"}.join("\n")
|
441
164
|
end
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
165
|
+
|
166
|
+
class State
|
167
|
+
attr_reader :commands
|
168
|
+
def initialize(interface, commands)
|
169
|
+
@interface = interface
|
170
|
+
@commands = commands
|
448
171
|
end
|
449
|
-
|
450
|
-
|
451
|
-
last_frame = c.frames.first
|
452
|
-
if last_frame
|
453
|
-
print "%s:%d", last_frame.file, last_frame.line
|
172
|
+
|
173
|
+
def proceed
|
454
174
|
end
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
def display_all_contexts
|
459
|
-
threads = Debugger.contexts.sort_by{|c| c.thnum}.each do |c|
|
460
|
-
display_context(c)
|
175
|
+
|
176
|
+
def print(*args)
|
177
|
+
@interface.print(*args)
|
461
178
|
end
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
Debugger.contexts.find{|c| c.thnum == thnum}
|
466
|
-
end
|
467
|
-
|
468
|
-
def debug_thread_info(input)
|
469
|
-
case input
|
470
|
-
when /^l(?:ist)?/
|
471
|
-
display_all_contexts
|
472
|
-
|
473
|
-
when /^c(?:ur(?:rent)?)?$/
|
474
|
-
display_context(Debugger.current_context)
|
475
|
-
|
476
|
-
when /^(?:sw(?:itch)?\s+)?(\d+)/
|
477
|
-
c = get_context($1.to_i)
|
478
|
-
if c == Debugger.current_context
|
479
|
-
print "It's the current thread.\n"
|
480
|
-
else
|
481
|
-
display_context(c)
|
482
|
-
c.stop_next = 1
|
483
|
-
c.thread.run
|
484
|
-
return :cont
|
485
|
-
end
|
486
|
-
|
487
|
-
when /^stop\s+(\d+)/
|
488
|
-
c = get_context($1.to_i)
|
489
|
-
if c == Debugger.current_context
|
490
|
-
print "It's the current thread.\n"
|
491
|
-
elsif c.thread.stop?
|
492
|
-
print "Already stopped.\n"
|
493
|
-
else
|
494
|
-
display_context(c)
|
495
|
-
c.set_suspend
|
496
|
-
end
|
497
|
-
|
498
|
-
when /^resume\s+(\d+)/
|
499
|
-
c = get_context($1.to_i)
|
500
|
-
if c == Debugger.current_context
|
501
|
-
print "It's the current thread.\n"
|
502
|
-
elsif !c.thread.stop?
|
503
|
-
print "Already running."
|
504
|
-
else
|
505
|
-
display_context(c)
|
506
|
-
c.thread.run
|
507
|
-
end
|
179
|
+
|
180
|
+
def confirm(*args)
|
181
|
+
'y'
|
508
182
|
end
|
509
|
-
end
|
510
183
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
return "\n" if lines == true
|
515
|
-
line = lines[line-1]
|
516
|
-
return "\n" unless line
|
517
|
-
return line.gsub(/^\s+/, '')
|
518
|
-
end
|
519
|
-
return "\n"
|
520
|
-
end
|
521
|
-
|
522
|
-
COMMANDS = {
|
523
|
-
'break' => %{
|
524
|
-
b[reak]\tlist breakpoints
|
525
|
-
b[reak] [file|class(:|.)]<line|method> [if expr] -
|
526
|
-
set breakpoint to some position, (optionally) if expr == true
|
527
|
-
},
|
528
|
-
'delete' => %{
|
529
|
-
del[ete][ nnn]\tdelete some or all breakpoints
|
530
|
-
},
|
531
|
-
'catch' => %{
|
532
|
-
cat[ch]\t\t\tshow catchpoint
|
533
|
-
cat[ch] <an Exception>\tset catchpoint to an exception
|
534
|
-
},
|
535
|
-
'display' => %{
|
536
|
-
disp[lay] <expression>\tadd expression into display expression list
|
537
|
-
},
|
538
|
-
'undisplay' => %{
|
539
|
-
undisp[lay][ nnn]\tdelete one particular or all display expressions
|
540
|
-
},
|
541
|
-
'cont' => %{
|
542
|
-
c[ont]\trun until program ends or hit breakpoint
|
543
|
-
},
|
544
|
-
'run' => %{
|
545
|
-
r[un]\talias for cont
|
546
|
-
},
|
547
|
-
'step' => %{
|
548
|
-
s[tep][ nnn]\tstep (into methods) one line or till line nnn
|
549
|
-
},
|
550
|
-
'next' => %{
|
551
|
-
n[ext][ nnn]\tgo over one line or till line nnn
|
552
|
-
},
|
553
|
-
'where' => %{
|
554
|
-
w[here]\tdisplay frames
|
555
|
-
},
|
556
|
-
'frame' => %{
|
557
|
-
f[rame]\talias for where
|
558
|
-
},
|
559
|
-
'list' => %{
|
560
|
-
l[ist][ (-|nn-mm)]\tlist program, '-' list backwards, nn-mm list given lines
|
561
|
-
},
|
562
|
-
'up' => %{
|
563
|
-
up[ nn]\tmove to higher frame
|
564
|
-
},
|
565
|
-
'down' => %{
|
566
|
-
down[ nn]\tmove to lower frame
|
567
|
-
},
|
568
|
-
'finish' => %{
|
569
|
-
fin[ish]\treturn to outer frame
|
570
|
-
},
|
571
|
-
'quit' => %{
|
572
|
-
q[uit]\texit from debugger
|
573
|
-
},
|
574
|
-
'trace' => %{
|
575
|
-
tr[ace] (on|off)\tset trace mode of current thread
|
576
|
-
tr[ace] (on|off) all\tset trace mode of all threads
|
577
|
-
},
|
578
|
-
'var' => %{
|
579
|
-
v[ar] g[lobal]\t\t\tshow global variables
|
580
|
-
v[ar] l[ocal]\t\t\tshow local variables
|
581
|
-
v[ar] i[nstance] <object>\tshow instance variables of object
|
582
|
-
v[ar] c[onst] <object>\t\tshow constants of object
|
583
|
-
},
|
584
|
-
'method' => %{
|
585
|
-
m[ethod] i[nstance] <obj>\tshow methods of object
|
586
|
-
m[ethod] <class|module>\t\tshow instance methods of class or module
|
587
|
-
},
|
588
|
-
'thread' => %{
|
589
|
-
th[read] l[ist]\t\t\tlist all threads
|
590
|
-
th[read] c[ur[rent]]\t\tshow current thread
|
591
|
-
th[read] [sw[itch]] <nnn>\tswitch thread context to nnn
|
592
|
-
th[read] stop <nnn>\t\tstop thread nnn
|
593
|
-
th[read] resume <nnn>\t\tresume thread nnn
|
594
|
-
},
|
595
|
-
'p' => %{
|
596
|
-
p expression\tevaluate expression and print its value
|
597
|
-
},
|
598
|
-
'eval' => %{
|
599
|
-
e[val] expression\tevaluate expression and print its value,
|
600
|
-
\t\t\talias for p
|
601
|
-
},
|
602
|
-
'pp' => %{
|
603
|
-
pp expression\tevaluate expression and print its value
|
604
|
-
},
|
605
|
-
'help' => %{
|
606
|
-
h[elp]\tprint this help
|
607
|
-
}
|
608
|
-
}
|
609
|
-
|
610
|
-
def debug_print_help(command)
|
611
|
-
print "ruby-debug help v.#{Debugger::VERSION}\n"
|
612
|
-
help = COMMANDS[command]
|
613
|
-
if help
|
614
|
-
print help.split("\n").map{|l| l.gsub(/^ +/, '')}.join("\n")
|
615
|
-
else
|
616
|
-
print "Available commands:\n"
|
617
|
-
require 'enumerator'
|
618
|
-
COMMANDS.keys.sort.enum_slice(12).each do |slice|
|
619
|
-
print slice.join(' ')
|
620
|
-
print "\n"
|
621
|
-
end
|
184
|
+
def file
|
185
|
+
print "No filename given.\n"
|
186
|
+
throw :debug_error
|
622
187
|
end
|
623
|
-
print "\n"
|
624
188
|
end
|
625
|
-
|
626
189
|
end
|
627
190
|
end
|