ruby-debug 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGES +41 -0
- data/ChangeLog +0 -0
- data/README +27 -13
- data/Rakefile +220 -0
- data/bin/rdebug +116 -42
- data/cli/ruby-debug.rb +33 -3
- data/cli/ruby-debug/command.rb +49 -12
- data/cli/ruby-debug/commands/breakpoints.rb +47 -64
- data/cli/ruby-debug/commands/control.rb +41 -13
- data/cli/ruby-debug/commands/display.rb +35 -18
- data/cli/ruby-debug/commands/enable.rb +159 -0
- data/cli/ruby-debug/commands/eval.rb +78 -4
- data/cli/ruby-debug/commands/frame.rb +67 -42
- data/cli/ruby-debug/commands/help.rb +21 -17
- data/cli/ruby-debug/commands/info.rb +210 -0
- data/cli/ruby-debug/commands/irb.rb +9 -1
- data/cli/ruby-debug/commands/list.rb +11 -8
- data/cli/ruby-debug/commands/method.rb +12 -23
- data/cli/ruby-debug/commands/script.rb +14 -9
- data/cli/ruby-debug/commands/settings.rb +174 -39
- data/cli/ruby-debug/commands/show.rb +193 -0
- data/cli/ruby-debug/commands/stepping.rb +15 -10
- data/cli/ruby-debug/commands/threads.rb +55 -56
- data/cli/ruby-debug/commands/variables.rb +27 -27
- data/cli/ruby-debug/helper.rb +134 -0
- data/cli/ruby-debug/interface.rb +46 -15
- data/cli/ruby-debug/processor.rb +156 -25
- data/doc/rdebug.1 +236 -0
- data/runner.sh +7 -0
- data/test/breakpoints.cmd +43 -0
- data/test/breakpoints.right +94 -0
- data/test/display.cmd +18 -0
- data/test/display.right +37 -0
- data/test/frame.cmd +21 -0
- data/test/frame.right +45 -0
- data/test/gcd.rb +18 -0
- data/test/help.cmd +12 -0
- data/test/help.right +4 -0
- data/test/helper.rb +87 -0
- data/test/info-var-bug.rb +45 -0
- data/test/info-var.cmd +23 -0
- data/test/info-var.right +47 -0
- data/test/info.cmd +12 -0
- data/test/info.right +35 -0
- data/test/quit.cmd +9 -0
- data/test/quit.right +22 -0
- data/test/setshow.cmd +44 -0
- data/test/setshow.right +73 -0
- data/test/stepping.cmd +17 -0
- data/test/stepping.right +40 -0
- data/test/tdebug.rb +196 -0
- data/test/test-breakpoints.rb +28 -0
- data/test/test-columnize.rb +46 -0
- data/test/test-display.rb +26 -0
- data/test/test-frame.rb +27 -0
- data/test/test-help.rb +44 -0
- data/test/test-info-var.rb +33 -0
- data/test/test-info.rb +28 -0
- data/test/test-quit.rb +28 -0
- data/test/test-ruby-debug-base.rb +76 -0
- data/test/test-setshow.rb +24 -0
- data/test/test-stepping.rb +26 -0
- metadata +63 -22
@@ -0,0 +1,159 @@
|
|
1
|
+
module Debugger
|
2
|
+
# Mix-in module to assist in command parsing.
|
3
|
+
module EnableDisableFunctions # :nodoc:
|
4
|
+
def enable_disable_breakpoints(is_enable, args)
|
5
|
+
breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
|
6
|
+
largest = breakpoints.inject(0){|largest, b| largest = b.id if b.id > largest}
|
7
|
+
if 0 == largest
|
8
|
+
print "No breakpoints have been set.\n"
|
9
|
+
return
|
10
|
+
end
|
11
|
+
args.each do |pos|
|
12
|
+
pos = get_int(pos, "#{is_enable} breakpoints", 1, largest)
|
13
|
+
return nil unless pos
|
14
|
+
breakpoints.each do |b|
|
15
|
+
if b.id == pos
|
16
|
+
b.enabled = ("Enable" == is_enable)
|
17
|
+
return
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def enable_disable_display(is_enable, args)
|
24
|
+
args.each do |pos|
|
25
|
+
pos = get_int(pos, "#{is_enable} display", 1, @state.display.size)
|
26
|
+
return nil unless pos
|
27
|
+
@state.display[pos-1][0] = ("Enable" == is_enable)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class EnableCommand < Command # :nodoc:
|
34
|
+
SubcmdStruct=Struct.new(:name, :min, :short_help) unless
|
35
|
+
defined?(SubcmdStruct)
|
36
|
+
Subcommands =
|
37
|
+
[
|
38
|
+
['breakpoints', 2, "Enable specified breakpoints"],
|
39
|
+
['display', 2, "Enable some expressions to be displayed when program stops"],
|
40
|
+
].map do |name, min, short_help|
|
41
|
+
SubcmdStruct.new(name, min, short_help)
|
42
|
+
end unless defined?(Subcommands)
|
43
|
+
|
44
|
+
def regexp
|
45
|
+
/^\s* en(?:able)? (?:\s+(.*))?$/ix
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute
|
49
|
+
if not @match[1]
|
50
|
+
print "\"enable\" must be followed \"display\", \"breakpoints\"" +
|
51
|
+
" or breakpoint numbers.\n"
|
52
|
+
else
|
53
|
+
args = @match[1].split(/[ \t]+/)
|
54
|
+
subcmd = args.shift.downcase
|
55
|
+
for try_subcmd in Subcommands do
|
56
|
+
if (subcmd.size >= try_subcmd.min) and
|
57
|
+
(try_subcmd.name[0..subcmd.size-1] == subcmd)
|
58
|
+
send("enable_#{try_subcmd.name}", args)
|
59
|
+
return
|
60
|
+
end
|
61
|
+
end
|
62
|
+
send("enable_breakpoints", args.unshift(subcmd))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def enable_breakpoints(args)
|
67
|
+
enable_disable_breakpoints("Enable", args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def enable_display(args)
|
71
|
+
enable_disable_display("Enable", args)
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def help_command
|
76
|
+
'enable'
|
77
|
+
end
|
78
|
+
|
79
|
+
def help(cmd)
|
80
|
+
s = %{
|
81
|
+
Enable some things.
|
82
|
+
This is used to cancel the effect of the "disable" command.
|
83
|
+
--
|
84
|
+
List of enable subcommands:
|
85
|
+
--
|
86
|
+
}
|
87
|
+
for subcmd in Subcommands do
|
88
|
+
s += "enable #{subcmd.name} -- #{subcmd.short_help}\n"
|
89
|
+
end
|
90
|
+
return s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class DisableCommand < Command # :nodoc:
|
96
|
+
SubcmdStruct=Struct.new(:name, :min, :short_help) unless
|
97
|
+
defined?(SubcmdStruct)
|
98
|
+
Subcommands =
|
99
|
+
[
|
100
|
+
['breakpoints', 2, "Disable specified breakpoints"],
|
101
|
+
['display', 2, "Disable some display expressions when program stops"],
|
102
|
+
].map do |name, min, short_help|
|
103
|
+
SubcmdStruct.new(name, min, short_help)
|
104
|
+
end unless defined?(Subcommands)
|
105
|
+
|
106
|
+
def regexp
|
107
|
+
/^\s* dis(?:able)? (?:\s+(.*))?$/ix
|
108
|
+
end
|
109
|
+
|
110
|
+
def execute
|
111
|
+
if not @match[1]
|
112
|
+
print "\"disable\" must be followed \"display\", \"breakpoints\"" +
|
113
|
+
" or breakpoint numbers.\n"
|
114
|
+
else
|
115
|
+
args = @match[1].split(/[ \t]+/)
|
116
|
+
subcmd = args.shift.downcase
|
117
|
+
for try_subcmd in Subcommands do
|
118
|
+
if (subcmd.size >= try_subcmd.min) and
|
119
|
+
(try_subcmd.name[0..subcmd.size-1] == subcmd)
|
120
|
+
send("disable_#{try_subcmd.name}", args)
|
121
|
+
return
|
122
|
+
end
|
123
|
+
end
|
124
|
+
send("disable_breakpoints", args.unshift(subcmd))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def disable_breakpoints(args)
|
129
|
+
enable_disable_breakpoints("Disable", args)
|
130
|
+
end
|
131
|
+
|
132
|
+
def disable_display(args)
|
133
|
+
enable_disable_display("Disable", args)
|
134
|
+
end
|
135
|
+
|
136
|
+
class << self
|
137
|
+
def help_command
|
138
|
+
'disable'
|
139
|
+
end
|
140
|
+
|
141
|
+
def help(cmd)
|
142
|
+
s = %{
|
143
|
+
Disable some things.
|
144
|
+
|
145
|
+
A disabled item is not forgotten, but has no effect until reenabled.
|
146
|
+
Use the "enable" command to have it take effect again.
|
147
|
+
--
|
148
|
+
List of disable subcommands:
|
149
|
+
--
|
150
|
+
}
|
151
|
+
for subcmd in Subcommands do
|
152
|
+
s += "disable #{subcmd.name} -- #{subcmd.short_help}\n"
|
153
|
+
end
|
154
|
+
return s
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end # module Debugger
|
@@ -4,13 +4,16 @@ module Debugger
|
|
4
4
|
binding = @state.context ? get_binding : TOPLEVEL_BINDING
|
5
5
|
$__dbg_interface = @state.interface
|
6
6
|
eval(<<-EOC, binding)
|
7
|
+
__dbg_verbose_save=$VERBOSE; $VERBOSE=false
|
7
8
|
def dbg_print(*args)
|
8
9
|
$__dbg_interface.print(*args)
|
9
10
|
end
|
11
|
+
remove_method :puts if self.respond_to?(:puts)
|
10
12
|
def dbg_puts(*args)
|
11
13
|
$__dbg_interface.print(*args)
|
12
14
|
$__dbg_interface.print("\n")
|
13
15
|
end
|
16
|
+
$VERBOSE=__dbg_verbose_save
|
14
17
|
EOC
|
15
18
|
yield binding
|
16
19
|
ensure
|
@@ -21,8 +24,6 @@ module Debugger
|
|
21
24
|
class EvalCommand < Command # :nodoc:
|
22
25
|
self.control = true
|
23
26
|
|
24
|
-
include EvalFunctions
|
25
|
-
|
26
27
|
register_setting_get(:autoeval) do
|
27
28
|
EvalCommand.unknown
|
28
29
|
end
|
@@ -70,8 +71,6 @@ module Debugger
|
|
70
71
|
class PPCommand < Command # :nodoc:
|
71
72
|
self.control = true
|
72
73
|
|
73
|
-
include EvalFunctions
|
74
|
-
|
75
74
|
def regexp
|
76
75
|
/^\s*pp\s+/
|
77
76
|
end
|
@@ -98,4 +97,79 @@ module Debugger
|
|
98
97
|
end
|
99
98
|
end
|
100
99
|
end
|
100
|
+
|
101
|
+
class PutLCommand < Command # :nodoc:
|
102
|
+
self.control = true
|
103
|
+
|
104
|
+
def regexp
|
105
|
+
/^\s*putl\s+/
|
106
|
+
end
|
107
|
+
|
108
|
+
def execute
|
109
|
+
out = StringIO.new
|
110
|
+
run_with_binding do |b|
|
111
|
+
vals = debug_eval(@match.post_match, b)
|
112
|
+
if vals.is_a?(Array)
|
113
|
+
vals = vals.map{|item| item.to_s}
|
114
|
+
print "%s\n", columnize(vals, self.class.settings[:width])
|
115
|
+
else
|
116
|
+
PP.pp(vals, out)
|
117
|
+
print out.string
|
118
|
+
end
|
119
|
+
end
|
120
|
+
rescue
|
121
|
+
out.puts $!.message
|
122
|
+
end
|
123
|
+
|
124
|
+
class << self
|
125
|
+
def help_command
|
126
|
+
'putl'
|
127
|
+
end
|
128
|
+
|
129
|
+
def help(cmd)
|
130
|
+
%{
|
131
|
+
putl expression\t\tevaluate expression, an array, and columnize its value
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class PSCommand < Command # :nodoc:
|
138
|
+
self.control = true
|
139
|
+
|
140
|
+
include EvalFunctions
|
141
|
+
|
142
|
+
def regexp
|
143
|
+
/^\s*ps\s+/
|
144
|
+
end
|
145
|
+
|
146
|
+
def execute
|
147
|
+
out = StringIO.new
|
148
|
+
run_with_binding do |b|
|
149
|
+
vals = debug_eval(@match.post_match, b)
|
150
|
+
if vals.is_a?(Array)
|
151
|
+
vals = vals.map{|item| item.to_s}
|
152
|
+
print "%s\n", columnize(vals.sort!, self.class.settings[:width])
|
153
|
+
else
|
154
|
+
PP.pp(vals, out)
|
155
|
+
print out.string
|
156
|
+
end
|
157
|
+
end
|
158
|
+
rescue
|
159
|
+
out.puts $!.message
|
160
|
+
end
|
161
|
+
|
162
|
+
class << self
|
163
|
+
def help_command
|
164
|
+
'ps'
|
165
|
+
end
|
166
|
+
|
167
|
+
def help(cmd)
|
168
|
+
%{
|
169
|
+
ps expression\tevaluate expression, an array, sort, and columnize its value
|
170
|
+
}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
101
175
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module Debugger
|
2
|
+
# Mix-in module to assist in command parsing.
|
2
3
|
module FrameFunctions # :nodoc:
|
3
4
|
def adjust_frame(frame_pos, absolute)
|
4
5
|
if absolute
|
@@ -12,10 +13,10 @@ module Debugger
|
|
12
13
|
end
|
13
14
|
|
14
15
|
if abs_frame_pos >= @state.context.stack_size then
|
15
|
-
print "Adjusting would put us beyond the oldest (initial) frame
|
16
|
+
print "Adjusting would put us beyond the oldest (initial) frame."
|
16
17
|
return
|
17
18
|
elsif abs_frame_pos < 0 then
|
18
|
-
print "Adjusting would put us beyond the newest (innermost) frame
|
19
|
+
print "Adjusting would put us beyond the newest (innermost) frame."
|
19
20
|
return
|
20
21
|
end
|
21
22
|
if @state.frame_pos != abs_frame_pos then
|
@@ -28,46 +29,83 @@ module Debugger
|
|
28
29
|
|
29
30
|
print_frame(@state.frame_pos, true)
|
30
31
|
end
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
|
33
|
+
def get_frame_call(prefix, pos)
|
34
|
+
id = @state.context.frame_method(pos)
|
35
|
+
klass = @state.context.frame_class(pos)
|
36
|
+
call_str = ""
|
37
|
+
if id
|
38
|
+
args = @state.context.frame_args(pos)
|
39
|
+
locals = @state.context.frame_locals(pos)
|
40
|
+
if Command.settings[:callstyle] != :short && klass
|
41
|
+
if Command.settings[:callstyle] == :tracked
|
42
|
+
arg_info = @state.context.frame_args_info(pos)
|
43
|
+
end
|
44
|
+
call_str << "#{klass}."
|
45
|
+
end
|
46
|
+
call_str << id.id2name
|
47
|
+
if args.any?
|
48
|
+
call_str << "("
|
49
|
+
args.each_with_index do |name, i|
|
50
|
+
case Command.settings[:callstyle]
|
51
|
+
when :short
|
52
|
+
call_str += "%s, " % [name]
|
53
|
+
when :last
|
54
|
+
klass = locals[name].class
|
55
|
+
if klass.inspect.size > 20+3
|
56
|
+
klass = klass.inspect[0..20]+"..."
|
57
|
+
end
|
58
|
+
call_str += "%s#%s, " % [name, klass]
|
59
|
+
when :tracked
|
60
|
+
if arg_info && arg_info.size > i
|
61
|
+
call_str += "#{name}: #{arg_info[i].inspect}, "
|
62
|
+
else
|
63
|
+
call_str += "%s, " % name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if call_str.size > self.class.settings[:width] - prefix.size
|
67
|
+
# Strip off trailing ', ' if any but add stuff for later trunc
|
68
|
+
call_str[-2..-1] = ",...XX"
|
69
|
+
break
|
70
|
+
end
|
71
|
+
end
|
72
|
+
call_str[-2..-1] = ")" # Strip off trailing ', ' if any
|
73
|
+
end
|
38
74
|
end
|
75
|
+
return call_str
|
39
76
|
end
|
40
77
|
|
41
78
|
def print_frame(pos, adjust = false)
|
42
79
|
file = @state.context.frame_file(pos)
|
43
80
|
line = @state.context.frame_line(pos)
|
44
|
-
id = @state.context.frame_method(pos)
|
45
81
|
klass = @state.context.frame_class(pos)
|
46
82
|
|
47
|
-
|
48
|
-
if id
|
49
|
-
method << " in '"
|
50
|
-
method << "#{klass}." if Command.settings[:frame_class_names] && klass
|
51
|
-
method << id.id2name
|
52
|
-
method << "'"
|
53
|
-
end
|
54
|
-
|
55
|
-
unless Command.settings[:frame_full_path]
|
83
|
+
unless Command.settings[:full_path]
|
56
84
|
path_components = file.split(/[\\\/]/)
|
57
85
|
if path_components.size > 3
|
58
86
|
path_components[0...-3] = '...'
|
59
87
|
file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
|
60
88
|
end
|
61
89
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
90
|
+
|
91
|
+
frame_num = "#%d " % pos
|
92
|
+
call_str = get_frame_call(frame_num, pos)
|
93
|
+
file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line]
|
94
|
+
print frame_num
|
95
|
+
unless call_str.empty?
|
96
|
+
print call_str
|
97
|
+
print ' '
|
98
|
+
if call_str.size + frame_num.size + file_line.size > self.class.settings[:width]
|
99
|
+
print "\n "
|
100
|
+
end
|
101
|
+
end
|
102
|
+
print file_line
|
103
|
+
print "\032\032%s:%d\n" % [CommandProcessor.canonic_file(file),
|
104
|
+
line] if ENV['EMACS'] && adjust
|
65
105
|
end
|
66
106
|
end
|
67
107
|
|
68
108
|
class WhereCommand < Command # :nodoc:
|
69
|
-
include FrameFunctions
|
70
|
-
|
71
109
|
def regexp
|
72
110
|
/^\s*(?:w(?:here)?|bt|backtrace)$/
|
73
111
|
end
|
@@ -103,19 +141,13 @@ module Debugger
|
|
103
141
|
end
|
104
142
|
|
105
143
|
class UpCommand < Command # :nodoc:
|
106
|
-
include FrameFunctions
|
107
|
-
|
108
144
|
def regexp
|
109
|
-
/^\s* u(?:p)? (?:\s+(.*))
|
145
|
+
/^\s* u(?:p)? (?:\s+(.*))?$/x
|
110
146
|
end
|
111
147
|
|
112
148
|
def execute
|
113
|
-
|
114
|
-
|
115
|
-
else
|
116
|
-
pos = get_int(@match[1], "Up")
|
117
|
-
return unless pos
|
118
|
-
end
|
149
|
+
pos = get_int(@match[1], "Up")
|
150
|
+
return unless pos
|
119
151
|
adjust_frame(pos, false)
|
120
152
|
end
|
121
153
|
|
@@ -133,19 +165,13 @@ module Debugger
|
|
133
165
|
end
|
134
166
|
|
135
167
|
class DownCommand < Command # :nodoc:
|
136
|
-
include FrameFunctions
|
137
|
-
|
138
168
|
def regexp
|
139
169
|
/^\s* down (?:\s+(.*))? .*$/x
|
140
170
|
end
|
141
171
|
|
142
172
|
def execute
|
143
|
-
|
144
|
-
|
145
|
-
else
|
146
|
-
pos = get_int(@match[1], "Down")
|
147
|
-
return unless pos
|
148
|
-
end
|
173
|
+
pos = get_int(@match[1], "Down")
|
174
|
+
return unless pos
|
149
175
|
adjust_frame(-pos, false)
|
150
176
|
end
|
151
177
|
|
@@ -163,7 +189,6 @@ module Debugger
|
|
163
189
|
end
|
164
190
|
|
165
191
|
class FrameCommand < Command # :nodoc:
|
166
|
-
include FrameFunctions
|
167
192
|
def regexp
|
168
193
|
/^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x
|
169
194
|
end
|
@@ -1,3 +1,9 @@
|
|
1
|
+
# Display a list of strings as a compact set of columns.
|
2
|
+
#
|
3
|
+
# Each column is only as wide as necessary.
|
4
|
+
# Columns are separated by two spaces (one was not legible enough).
|
5
|
+
# Adapted from the routine of the same name in cmd.py
|
6
|
+
|
1
7
|
module Debugger
|
2
8
|
class HelpCommand < Command # :nodoc:
|
3
9
|
self.control = true
|
@@ -7,27 +13,25 @@ module Debugger
|
|
7
13
|
end
|
8
14
|
|
9
15
|
def execute
|
10
|
-
print "ruby-debug help v#{Debugger::VERSION}\n"
|
16
|
+
print "ruby-debug help v#{Debugger::VERSION}\n" unless
|
17
|
+
self.class.settings[:debuggertesting]
|
11
18
|
cmds = @state.commands.select{ |cmd| [cmd.help_command].flatten.include?(@match[1]) }
|
12
19
|
unless cmds.empty?
|
13
20
|
help = cmds.map{ |cmd| cmd.help(@match[1]) }.join
|
14
|
-
|
21
|
+
help = help.split("\n").map{|l| l.gsub(/^ +/, '')}
|
22
|
+
help.shift if help.first && help.first.empty?
|
23
|
+
help.pop if help.last && help.last.empty?
|
24
|
+
print help.join("\n")
|
15
25
|
else
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
print "%s\n", buf
|
25
|
-
buf = "#{cmd} "
|
26
|
-
else
|
27
|
-
buf << cmd << ' '
|
28
|
-
end
|
26
|
+
if @match[1]
|
27
|
+
print "Undefined command: \"#{@match[1]}\". Try \"help\"."
|
28
|
+
else
|
29
|
+
print "Type 'help <command-name>' for help on a specific command\n\n"
|
30
|
+
print "Available commands:\n"
|
31
|
+
cmds = @state.commands.map{ |cmd| cmd.help_command }
|
32
|
+
cmds = cmds.flatten.uniq.sort
|
33
|
+
print columnize(cmds, self.class.settings[:width])
|
29
34
|
end
|
30
|
-
print "%s\n", buf if buf.length > 0
|
31
35
|
end
|
32
36
|
print "\n"
|
33
37
|
end
|
@@ -45,4 +49,4 @@ module Debugger
|
|
45
49
|
end
|
46
50
|
end
|
47
51
|
end
|
48
|
-
end
|
52
|
+
end
|