ruby-debug 0.2-mswin32 → 0.3-mswin32
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/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,76 @@
|
|
1
|
+
module Debugger
|
2
|
+
class Command
|
3
|
+
class << self
|
4
|
+
def commands
|
5
|
+
@commands ||= []
|
6
|
+
end
|
7
|
+
|
8
|
+
def inherited(klass)
|
9
|
+
klass.instance_variable_set("@event",
|
10
|
+
klass.instance_variable_get("@event") || true)
|
11
|
+
klass.instance_variable_set("@control",
|
12
|
+
klass.instance_variable_get("@control") || false)
|
13
|
+
commands << klass
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_commands
|
17
|
+
dir = File.dirname(__FILE__)
|
18
|
+
Dir[File.join(dir, 'commands', '*')].each do |file|
|
19
|
+
require file
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :control
|
24
|
+
attr_accessor :event
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(state)
|
28
|
+
@state = state
|
29
|
+
end
|
30
|
+
|
31
|
+
def match(input)
|
32
|
+
@match = regexp.match(input)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def print(*args)
|
38
|
+
@state.print(*args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def confirm(msg)
|
42
|
+
@state.confirm(msg) == 'y'
|
43
|
+
end
|
44
|
+
|
45
|
+
def debug_eval(str)
|
46
|
+
begin
|
47
|
+
val = eval(str, @state.binding)
|
48
|
+
rescue StandardError, ScriptError => e
|
49
|
+
at = eval("caller(1)", @state.binding)
|
50
|
+
print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
|
51
|
+
for i in at
|
52
|
+
print "\tfrom %s\n", i
|
53
|
+
end
|
54
|
+
throw :debug_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def debug_silent_eval(str)
|
59
|
+
begin
|
60
|
+
eval(str, @state.binding)
|
61
|
+
rescue StandardError, ScriptError
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def line_at(file, line)
|
67
|
+
Debugger.line_at(file, line)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_context(thnum)
|
71
|
+
Debugger.contexts.find{|c| c.thnum == thnum}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
Command.load_commands
|
76
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Debugger
|
2
|
+
class AddBreakpoint < Command
|
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
|
+
file, pos, expr = @match.captures
|
23
|
+
else
|
24
|
+
file, pos, expr = @match.captures[1..-1]
|
25
|
+
end
|
26
|
+
|
27
|
+
if file =~ /^\d+$/
|
28
|
+
pos = file
|
29
|
+
file = File.basename(@state.file)
|
30
|
+
else
|
31
|
+
if pos !~ /^\d+$/
|
32
|
+
klass = debug_silent_eval(file)
|
33
|
+
if klass && !klass.kind_of?(Module)
|
34
|
+
print "Unknown class #{file}\n"
|
35
|
+
throw :debug_error
|
36
|
+
end
|
37
|
+
file = klass.name if klass
|
38
|
+
else
|
39
|
+
file = File.basename(file)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if pos =~ /^\d+$/
|
44
|
+
pos = pos.to_i
|
45
|
+
else
|
46
|
+
pos = pos.intern.id2name
|
47
|
+
end
|
48
|
+
|
49
|
+
Debugger.add_breakpoint file, pos, expr
|
50
|
+
print "Set breakpoint %d at %s:%s\n", Debugger.breakpoints.size, file, pos.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
def help_command
|
55
|
+
'break'
|
56
|
+
end
|
57
|
+
|
58
|
+
def help(cmd)
|
59
|
+
%{
|
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
|
68
|
+
self.control = true
|
69
|
+
|
70
|
+
def regexp
|
71
|
+
/^\s*b(?:reak)?$/
|
72
|
+
end
|
73
|
+
|
74
|
+
def execute
|
75
|
+
unless Debugger.breakpoints.empty?
|
76
|
+
print "Breakpoints:\n"
|
77
|
+
Debugger.breakpoints.each_with_index do |b, n|
|
78
|
+
if b.expr.nil?
|
79
|
+
print " %d %s:%s\n", n+1, b.source, b.pos
|
80
|
+
else
|
81
|
+
print " %d %s:%s if %s\n", n+1, b.source, b.pos, b.expr
|
82
|
+
end
|
83
|
+
end
|
84
|
+
print "\n"
|
85
|
+
else
|
86
|
+
print "No breakpoints\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class << self
|
91
|
+
def help_command
|
92
|
+
'break'
|
93
|
+
end
|
94
|
+
|
95
|
+
def help(cmd)
|
96
|
+
%{
|
97
|
+
b[reak]\tlist breakpoints
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class DeleteBreakpointCommand < Command
|
104
|
+
self.control = true
|
105
|
+
|
106
|
+
def regexp
|
107
|
+
/^\s*del(?:ete)?(?:\s+(\d+))?$/
|
108
|
+
end
|
109
|
+
|
110
|
+
def execute
|
111
|
+
pos = @match[1]
|
112
|
+
unless pos
|
113
|
+
if confirm("Clear all breakpoints? (y/n) ")
|
114
|
+
Debugger.breakpoints.clear
|
115
|
+
end
|
116
|
+
else
|
117
|
+
pos = pos.to_i
|
118
|
+
unless Debugger.breakpoints.delete_at(pos-1)
|
119
|
+
print "Breakpoint %d is not defined\n", pos
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class << self
|
125
|
+
def help_command
|
126
|
+
'delete'
|
127
|
+
end
|
128
|
+
|
129
|
+
def help(cmd)
|
130
|
+
%{
|
131
|
+
del[ete][ nnn]\tdelete some or all breakpoints
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Debugger
|
2
|
+
class CatchCommand < Command
|
3
|
+
self.control = true
|
4
|
+
|
5
|
+
def regexp
|
6
|
+
/^\s*cat(?:ch)?(?:\s+(.+))?$/
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
if excn = @match[1]
|
11
|
+
if excn == 'off'
|
12
|
+
Debugger.catchpoint = nil
|
13
|
+
print "Clear catchpoint.\n"
|
14
|
+
else
|
15
|
+
Debugger.catchpoint = excn
|
16
|
+
print "Set catchpoint %s.\n", excn
|
17
|
+
end
|
18
|
+
else
|
19
|
+
if Debugger.catchpoint
|
20
|
+
print "Catchpoint %s.\n", Debugger.catchpoint
|
21
|
+
else
|
22
|
+
print "No catchpoint.\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def help_command
|
29
|
+
'catch'
|
30
|
+
end
|
31
|
+
|
32
|
+
def help(cmd)
|
33
|
+
%{
|
34
|
+
cat[ch]\t\t\tshow catchpoint
|
35
|
+
cat[ch] <an Exception>\tset catchpoint to an exception
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Debugger
|
2
|
+
class QuitCommand < Command
|
3
|
+
self.control = true
|
4
|
+
|
5
|
+
def regexp
|
6
|
+
/^\s*q(?:uit)?\s*$/
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute
|
10
|
+
if confirm("Really quit? (y/n) ")
|
11
|
+
exit! # exit -> exit!: No graceful way to stop threads...
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def help_command
|
17
|
+
'quit'
|
18
|
+
end
|
19
|
+
|
20
|
+
def help(cmd)
|
21
|
+
%{
|
22
|
+
q[uit]\texit from debugger
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class InterruptCommand < Command
|
29
|
+
self.event = false
|
30
|
+
self.control = true
|
31
|
+
|
32
|
+
def regexp
|
33
|
+
/^\s*i(?:nterrupt)?\s*$/
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute
|
37
|
+
unless Debugger.interrupt_last
|
38
|
+
context = Debugger.contexts.find{ |c| c.thread == Thread.main }
|
39
|
+
context.interrupt
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def help_command
|
45
|
+
'interrupt'
|
46
|
+
end
|
47
|
+
|
48
|
+
def help(cmd)
|
49
|
+
%{
|
50
|
+
i[nterrupt]\tinterrupt the program
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Debugger
|
2
|
+
module DisplayFunctions
|
3
|
+
def display_expression(exp)
|
4
|
+
print "%s = %s\n", exp, debug_silent_eval(exp).to_s
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class AddDisplayCommand < Command
|
9
|
+
include DisplayFunctions
|
10
|
+
|
11
|
+
def regexp
|
12
|
+
/^\s*disp(?:lay)?\s+(.+)$/
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
exp = @match[1]
|
17
|
+
@state.display.push [true, exp]
|
18
|
+
print "%d: ", @state.display.size
|
19
|
+
display_expression(exp)
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def help_command
|
24
|
+
'display'
|
25
|
+
end
|
26
|
+
|
27
|
+
def help(cmd)
|
28
|
+
%{
|
29
|
+
disp[lay] <expression>\tadd expression into display expression list
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class DisplayCommand < Command
|
36
|
+
include DisplayFunctions
|
37
|
+
|
38
|
+
def initialize(state)
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def regexp
|
43
|
+
/^\s*disp(?:lay)?$/
|
44
|
+
end
|
45
|
+
|
46
|
+
def execute
|
47
|
+
n = 1
|
48
|
+
for d in @state.display
|
49
|
+
if d[0]
|
50
|
+
print "%d: ", n
|
51
|
+
display_expression(d[1])
|
52
|
+
end
|
53
|
+
n += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class << self
|
58
|
+
def help_command
|
59
|
+
'display'
|
60
|
+
end
|
61
|
+
|
62
|
+
def help(cmd)
|
63
|
+
%{
|
64
|
+
disp[lay]\t\tdisplay expression list
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class DeleteDisplayCommand < Command
|
71
|
+
include DisplayFunctions
|
72
|
+
|
73
|
+
def regexp
|
74
|
+
/^\s*undisp(?:lay)?(?:\s+(\d+))?$/
|
75
|
+
end
|
76
|
+
|
77
|
+
def execute
|
78
|
+
unless pos = @match[1]
|
79
|
+
if confirm("Clear all expressions? (y/n) ")
|
80
|
+
for d in @state.display
|
81
|
+
d[0] = false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
pos = pos.to_i
|
86
|
+
if @state.display[pos-1]
|
87
|
+
@state.display[pos-1][0] = false
|
88
|
+
else
|
89
|
+
print "Display expression %d is not defined\n", pos
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class << self
|
95
|
+
def help_command
|
96
|
+
'undisplay'
|
97
|
+
end
|
98
|
+
|
99
|
+
def help(cmd)
|
100
|
+
%{
|
101
|
+
undisp[lay][ nnn]\tdelete one particular or all display expressions
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Debugger
|
2
|
+
class EvalCommand < Command
|
3
|
+
def regexp
|
4
|
+
/^\s*(\s*p|e(?:val)?)\s+/
|
5
|
+
end
|
6
|
+
|
7
|
+
def execute
|
8
|
+
print "%s\n", debug_eval(@match.post_match).inspect
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def help_command
|
13
|
+
%w|p eval|
|
14
|
+
end
|
15
|
+
|
16
|
+
def help(cmd)
|
17
|
+
if cmd == 'p'
|
18
|
+
%{
|
19
|
+
p expression\tevaluate expression and print its value
|
20
|
+
}
|
21
|
+
else
|
22
|
+
%{
|
23
|
+
e[val] expression\tevaluate expression and print its value,
|
24
|
+
\t\t\talias for p
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class PPCommand < Command
|
32
|
+
def regexp
|
33
|
+
/^\s*pp\s+/
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute
|
37
|
+
out = StringIO.new
|
38
|
+
PP.pp(debug_eval(@match.post_match), out) rescue out.puts $!.message
|
39
|
+
print out.string
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def help_command
|
44
|
+
'pp'
|
45
|
+
end
|
46
|
+
|
47
|
+
def help(cmd)
|
48
|
+
%{
|
49
|
+
pp expression\tevaluate expression and print its value
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|