ruby-debug 0.9.3 → 0.10.0
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/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
|