ruby-debug 0.10.4 → 0.10.5.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +5 -0
- data/CHANGES +17 -0
- data/ChangeLog +6086 -3711
- data/README +39 -0
- data/Rakefile +67 -82
- data/cli/ruby-debug/commands/breakpoints.rb +4 -2
- data/cli/ruby-debug/commands/edit.rb +3 -2
- data/cli/ruby-debug/commands/info.rb +5 -4
- data/cli/ruby-debug/commands/irb.rb +7 -8
- data/cli/ruby-debug/commands/list.rb +1 -1
- data/cli/ruby-debug/commands/set.rb +7 -1
- data/cli/ruby-debug/commands/show.rb +8 -3
- data/cli/ruby-debug/processor.rb +10 -4
- data/doc/rdebug.1 +1 -1
- data/rdbg.rb +1 -1
- data/test/base/base.rb +7 -4
- data/test/base/binding.rb +3 -12
- data/test/base/catchpoint.rb +2 -9
- data/test/base/load.rb +18 -14
- data/test/base/reload_bug.rb +2 -2
- data/test/cli/commands/catchpoint_test.rb +1 -13
- data/test/cli/commands/unit/regexp.rb +2 -8
- data/test/data/annotate.cmd +2 -2
- data/test/data/annotate.right +8 -8
- data/test/data/at-exit.cmd +4 -0
- data/test/data/at-exit.right +12 -0
- data/test/data/break_bad.cmd +3 -5
- data/test/data/break_bad.right +4 -6
- data/test/data/break_tracelines.cmd +9 -0
- data/test/data/break_tracelines.right +17 -0
- data/test/data/breakpoints-basename.cmd +2 -0
- data/test/data/breakpoints-basename.right +10 -0
- data/test/data/breakpoints.cmd +0 -1
- data/test/data/breakpoints.right +1 -3
- data/test/data/catch.cmd +1 -0
- data/test/data/catch.right +2 -0
- data/test/data/continue_bad.cmd +4 -0
- data/test/data/continue_bad.right +9 -0
- data/test/data/ctrl.right +2 -1
- data/test/data/dollar-0.right +3 -2
- data/test/data/dollar-0a.right +1 -0
- data/test/data/dollar-0b.right +1 -0
- data/test/data/edit.cmd +1 -1
- data/test/data/edit.right +4 -4
- data/test/data/emacs_basic.cmd +1 -34
- data/test/data/emacs_basic.right +10 -92
- data/test/data/frame.cmd +0 -3
- data/test/data/frame.right +0 -4
- data/test/data/info-file-break.cmd +4 -0
- data/test/data/info-file-break.right +11 -0
- data/test/data/info-thread.right +4 -4
- data/test/data/info-var-bug2.right +2 -2
- data/test/data/info.cmd +0 -1
- data/test/data/info.right +1 -5
- data/test/data/linetrace-jruby.right +23 -0
- data/test/data/list.right +13 -13
- data/test/data/output.right +4 -4
- data/test/data/post-mortem-osx.right +5 -4
- data/test/data/quit.right +9 -0
- data/test/data/raise-jruby.right +26 -0
- data/test/data/raise.right +1 -1
- data/test/data/save.cmd +1 -0
- data/test/data/save.right +4 -2
- data/test/data/stepping.cmd +2 -2
- data/test/data/stepping.right +4 -4
- data/test/data/test-init.right +2 -2
- data/test/data/trace-jruby.right +14 -0
- data/test/example/a/example.rb +1 -0
- data/test/example/at-exit.rb +3 -0
- data/test/example/b/example.rb +1 -0
- data/test/{bp_loop_issue.rb → example/bp_loop_issue.rb} +0 -0
- data/test/example/breakpoints-basename.rb +2 -0
- data/test/{brkpt-class-bug.rb → example/brkpt-class-bug.rb} +0 -0
- data/test/{classes.rb → example/classes.rb} +0 -0
- data/test/{dollar-0.rb → example/dollar-0.rb} +1 -0
- data/test/{except-bug1.rb → example/except-bug1.rb} +0 -0
- data/test/file with space.rb b/data/test/example/file with → space.rb +0 -0
- data/test/{gcd.rb → example/gcd.rb} +0 -0
- data/test/{info-var-bug.rb → example/info-var-bug.rb} +0 -0
- data/test/{info-var-bug2.rb → example/info-var-bug2.rb} +0 -0
- data/test/{null.rb → example/null.rb} +0 -0
- data/test/{output.rb → example/output.rb} +0 -0
- data/test/{pm-bug.rb → example/pm-bug.rb} +0 -0
- data/test/{pm.rb → example/pm.rb} +0 -0
- data/test/{raise.rb → example/raise.rb} +0 -0
- data/test/helper.rb +52 -34
- data/test/rdebug-save.1 +2 -2
- data/test/test-annotate.rb +4 -16
- data/test/test-at-exit.rb +13 -0
- data/test/test-break-bad.rb +14 -25
- data/test/test-breakpoints.rb +13 -14
- data/test/test-brkpt-class-bug.rb +3 -16
- data/test/test-catch.rb +3 -15
- data/test/test-condition.rb +3 -15
- data/test/test-display.rb +3 -15
- data/test/test-dollar-0.rb +23 -35
- data/test/test-edit.rb +4 -16
- data/test/test-emacs-basic.rb +4 -17
- data/test/test-enable.rb +3 -15
- data/test/test-except-bug1.rb +6 -21
- data/test/test-file-with-space.rb +3 -15
- data/test/test-finish.rb +11 -23
- data/test/test-frame.rb +14 -20
- data/test/test-hist.rb +6 -10
- data/test/test-info-thread.rb +13 -21
- data/test/test-info-var.rb +20 -37
- data/test/test-info.rb +16 -15
- data/test/test-list.rb +3 -14
- data/test/test-method.rb +9 -23
- data/test/test-output.rb +3 -16
- data/test/test-pm.rb +16 -38
- data/test/test-quit.rb +3 -20
- data/test/test-raise.rb +3 -15
- data/test/test-save.rb +12 -21
- data/test/test-setshow.rb +3 -15
- data/test/test-source.rb +3 -15
- data/test/test-stepping.rb +3 -15
- data/test/test-trace.rb +22 -45
- metadata +199 -159
- data/VERSION +0 -3
- data/cli/ruby-debug/commands/continue.RB +0 -48
- data/cli/ruby-debug/commands/disassemble.RB +0 -38
- data/cli/ruby-debug/commands/raise.RB +0 -41
- data/cli/ruby-debug/commands/source.RB +0 -44
- data/cli/ruby-debug/processor.RB +0 -484
- data/runner.sh +0 -7
- data/test/except-bug2.rb +0 -7
- data/test/scope-test.rb +0 -8
- data/test/tvar.rb +0 -3
data/VERSION
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
module Debugger
|
2
|
-
|
3
|
-
# Implements debugger "continue" command.
|
4
|
-
class ContinueCommand < Command
|
5
|
-
self.allow_in_post_mortem = false
|
6
|
-
self.need_context = true
|
7
|
-
def regexp
|
8
|
-
/^\s* c(?:ont(?:inue)?)? (?:\s+(.*))? $/x
|
9
|
-
end
|
10
|
-
|
11
|
-
def execute
|
12
|
-
unless @state.context
|
13
|
-
errmsg "We are not in a state we can continue.\n"
|
14
|
-
return
|
15
|
-
end
|
16
|
-
if @match[1] && !@state.context.dead?
|
17
|
-
if '-' == @match[1]
|
18
|
-
Debugger.stop if Debugger.started?
|
19
|
-
else
|
20
|
-
filename = File.expand_path(@state.file)
|
21
|
-
line_number = get_int(@match[1], "Continue", 0, nil, 0)
|
22
|
-
return unless line_number
|
23
|
-
unless LineCache.trace_line_numbers(filename).member?(line_number)
|
24
|
-
errmsg("Line %d is not a stopping point in file \"%s\".\n",
|
25
|
-
line_number, filename)
|
26
|
-
return
|
27
|
-
end
|
28
|
-
@state.context.set_breakpoint(filename, line_number)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
@state.proceed
|
32
|
-
end
|
33
|
-
|
34
|
-
class << self
|
35
|
-
def help_command
|
36
|
-
'continue'
|
37
|
-
end
|
38
|
-
|
39
|
-
def help(cmd)
|
40
|
-
%{
|
41
|
-
c[ont[inue]][ nnn | -]\trun until program ends, hits a breakpoint or reaches line nnn.
|
42
|
-
|
43
|
-
If - is given then we issue a Debugger.stop to remove tracing the program continues at full speed.
|
44
|
-
}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
module Debugger
|
2
|
-
|
3
|
-
require 'pp'
|
4
|
-
require 'nodepp'
|
5
|
-
require 'classtree'
|
6
|
-
require 'parse_tree'
|
7
|
-
class Disassemble < Command # :nodoc:
|
8
|
-
self.allow_in_control = false
|
9
|
-
@@parse_tree = ParseTree.new(true)
|
10
|
-
|
11
|
-
def regexp
|
12
|
-
/^\s*(dis(?:assemble)?)\s+/
|
13
|
-
end
|
14
|
-
|
15
|
-
def execute
|
16
|
-
expr = @match ? @match.post_match : @input
|
17
|
-
binding = @state.context ? get_binding : TOPLEVEL_BINDING
|
18
|
-
method_str = "method(:#{expr})"
|
19
|
-
if method_obj = debug_eval(method_str, binding)
|
20
|
-
print @@parse_tree.parse_tree_for_method(method_obj.class,
|
21
|
-
method_str).inspect
|
22
|
-
print "#{method_obj}\n"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class << self
|
27
|
-
def help_command
|
28
|
-
%w|disassemble method-name|
|
29
|
-
end
|
30
|
-
|
31
|
-
def help(cmd)
|
32
|
-
%{
|
33
|
-
dis[assemble] method-name\tdo live unparsing of method name
|
34
|
-
}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end if false
|
38
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Debugger
|
2
|
-
class RaiseCommand < Command # :nodoc:
|
3
|
-
self.allow_in_control = false
|
4
|
-
|
5
|
-
def regexp
|
6
|
-
/^\s* raise
|
7
|
-
(?:\s+ (\S+))? \s* $/ix
|
8
|
-
end
|
9
|
-
|
10
|
-
def execute
|
11
|
-
excn = @match[1]
|
12
|
-
exception =
|
13
|
-
if not excn
|
14
|
-
# No args given.
|
15
|
-
RuntimeError
|
16
|
-
else
|
17
|
-
unless debug_eval("#{excn}.is_a?(Class)", binding)
|
18
|
-
errmsg "#{excn} is not known to be a Class\n"
|
19
|
-
return
|
20
|
-
end
|
21
|
-
debug_eval(excn, binding)
|
22
|
-
end
|
23
|
-
@state.exception = exception
|
24
|
-
@state.proceed
|
25
|
-
end
|
26
|
-
|
27
|
-
class << self
|
28
|
-
def help_command
|
29
|
-
'raise'
|
30
|
-
end
|
31
|
-
|
32
|
-
def help(cmd)
|
33
|
-
%{
|
34
|
-
raise EXCEPTION
|
35
|
-
|
36
|
-
Raise an exception in the debugged program."
|
37
|
-
}
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module Debugger
|
2
|
-
# Implements debugger "source" command.
|
3
|
-
class SourceCommand < Command
|
4
|
-
self.allow_in_control = true
|
5
|
-
|
6
|
-
def regexp
|
7
|
-
/^\s* so(?:urce)? (\s+ -v)? \s+ (.+) $/x
|
8
|
-
end
|
9
|
-
|
10
|
-
def execute
|
11
|
-
if 3 == @match.size then
|
12
|
-
verbose=true
|
13
|
-
file=@match[2]
|
14
|
-
else
|
15
|
-
verbose=false
|
16
|
-
file=@match[1]
|
17
|
-
end
|
18
|
-
|
19
|
-
file = File.expand_path(file).strip
|
20
|
-
unless File.exist?(file)
|
21
|
-
errmsg "Command file '#{file}' is not found\n"
|
22
|
-
return
|
23
|
-
end
|
24
|
-
if @state and @state.interface
|
25
|
-
@state.interface.command_queue += File.open(file).readlines
|
26
|
-
else
|
27
|
-
Debugger.run_script(file, @state, verbose)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
def help_command
|
33
|
-
'source'
|
34
|
-
end
|
35
|
-
|
36
|
-
def help(cmd)
|
37
|
-
%{
|
38
|
-
source FILE\texecutes a file containing debugger commands
|
39
|
-
}
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
data/cli/ruby-debug/processor.RB
DELETED
@@ -1,484 +0,0 @@
|
|
1
|
-
require 'ruby-debug/interface'
|
2
|
-
require 'ruby-debug/command'
|
3
|
-
|
4
|
-
module Debugger
|
5
|
-
|
6
|
-
# Should this be a mixin?
|
7
|
-
class Processor # :nodoc
|
8
|
-
attr_accessor :interface
|
9
|
-
attr_reader :processor
|
10
|
-
attr_reader :commands
|
11
|
-
|
12
|
-
# Format msg with gdb-style annotation header
|
13
|
-
def afmt(msg, newline="\n")
|
14
|
-
"\032\032#{msg}#{newline}"
|
15
|
-
end
|
16
|
-
|
17
|
-
def aprint(msg)
|
18
|
-
print afmt(msg) if Debugger.annotate.to_i > 2
|
19
|
-
end
|
20
|
-
|
21
|
-
# FIXME: use delegate?
|
22
|
-
def errmsg(*args)
|
23
|
-
@interface.errmsg(*args)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Callers of this routine should make sure to use comma to
|
27
|
-
# separate format argments rather than %. Otherwise it seems that
|
28
|
-
# if the string you want to print has format specifier, which
|
29
|
-
# could happen if you are trying to show say a source-code line
|
30
|
-
# with "puts" or "print" in it, this print routine will give an
|
31
|
-
# error saying it is looking for more arguments.
|
32
|
-
def print(*args)
|
33
|
-
@interface.print(*args)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
class CommandProcessor < Processor # :nodoc:
|
39
|
-
attr_reader :display
|
40
|
-
|
41
|
-
# FIXME: get from Command regexp method.
|
42
|
-
@@Show_breakpoints_postcmd = [
|
43
|
-
/^\s*b(?:reak)?/,
|
44
|
-
/^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix,
|
45
|
-
/^\s*del(?:ete)?(?:\s+(.*))?$/ix,
|
46
|
-
/^\s* dis(?:able)? (?:\s+(.*))?$/ix,
|
47
|
-
/^\s* en(?:able)? (?:\s+(.*))?$/ix,
|
48
|
-
# "tbreak", "clear",
|
49
|
-
]
|
50
|
-
@@Show_annotations_run = [
|
51
|
-
/^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/,
|
52
|
-
/^\s*fin(?:ish)?$/,
|
53
|
-
/^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/,
|
54
|
-
/^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/
|
55
|
-
]
|
56
|
-
|
57
|
-
@@Show_annotations_postcmd = [
|
58
|
-
/^\s* down (?:\s+(.*))? .*$/x,
|
59
|
-
/^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x,
|
60
|
-
/^\s* u(?:p)? (?:\s+(.*))?$/x
|
61
|
-
]
|
62
|
-
|
63
|
-
def initialize(interface = LocalInterface.new)
|
64
|
-
@interface = interface
|
65
|
-
@commands = []
|
66
|
-
@display = []
|
67
|
-
|
68
|
-
@mutex = Mutex.new
|
69
|
-
@last_cmd = nil
|
70
|
-
@last_file = nil # Filename the last time we stopped
|
71
|
-
@last_line = nil # line number the last time we stopped
|
72
|
-
@debugger_breakpoints_were_empty = false # Show breakpoints 1st time
|
73
|
-
@debugger_displays_were_empty = true # No display 1st time
|
74
|
-
@debugger_context_was_dead = true # Assume we haven't started.
|
75
|
-
end
|
76
|
-
|
77
|
-
def interface=(interface)
|
78
|
-
@mutex.synchronize do
|
79
|
-
@interface.close if @interface
|
80
|
-
@interface = interface
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
require 'pathname' # For cleanpath
|
85
|
-
|
86
|
-
# Regularize file name.
|
87
|
-
# This is also used as a common funnel place if basename is
|
88
|
-
# desired or if we are working remotely and want to change the
|
89
|
-
# basename. Or we are eliding filenames.
|
90
|
-
def self.canonic_file(filename)
|
91
|
-
# For now we want resolved filenames
|
92
|
-
if Command.settings[:basename]
|
93
|
-
File.basename(filename)
|
94
|
-
else
|
95
|
-
# Cache this?
|
96
|
-
Pathname.new(filename).cleanpath.to_s
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.print_location_and_text(file, line)
|
101
|
-
file_line = "%s:%s\n%s" % [canonic_file(file), line,
|
102
|
-
Debugger.line_at(file, line)]
|
103
|
-
# FIXME: use annotations routines
|
104
|
-
if Debugger.annotate.to_i > 2
|
105
|
-
file_line = "\032\032source #{file_line}"
|
106
|
-
elsif ENV['EMACS']
|
107
|
-
file_line = "\032\032#{file_line}"
|
108
|
-
end
|
109
|
-
print file_line
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.protect(mname)
|
113
|
-
alias_method "__#{mname}", mname
|
114
|
-
module_eval %{
|
115
|
-
def #{mname}(*args)
|
116
|
-
@mutex.synchronize do
|
117
|
-
return unless @interface
|
118
|
-
__#{mname}(*args)
|
119
|
-
end
|
120
|
-
rescue IOError, Errno::EPIPE
|
121
|
-
self.interface = nil
|
122
|
-
rescue SignalException
|
123
|
-
raise
|
124
|
-
rescue Exception => e
|
125
|
-
unless
|
126
|
-
print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
|
127
|
-
print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
|
128
|
-
end
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
|
-
def at_breakpoint(context, breakpoint)
|
133
|
-
aprint 'stopped' if Debugger.annotate.to_i > 2
|
134
|
-
n = Debugger.breakpoints.index(breakpoint) + 1
|
135
|
-
file = CommandProcessor.canonic_file(breakpoint.source)
|
136
|
-
line = breakpoint.pos
|
137
|
-
if Debugger.annotate.to_i > 2
|
138
|
-
print afmt("source #{file}:#{line}")
|
139
|
-
end
|
140
|
-
print "Breakpoint %d at %s:%s\n", n, file, line
|
141
|
-
end
|
142
|
-
protect :at_breakpoint
|
143
|
-
|
144
|
-
def at_catchpoint(context, excpt)
|
145
|
-
aprint 'stopped' if Debugger.annotate.to_i > 2
|
146
|
-
file = CommandProcessor.canonic_file(context.frame_file(0))
|
147
|
-
line = context.frame_line(0)
|
148
|
-
print afmt("%s:%d" % [file, line]) if ENV['EMACS']
|
149
|
-
print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class
|
150
|
-
fs = context.stack_size
|
151
|
-
tb = caller(0)[-fs..-1]
|
152
|
-
if tb
|
153
|
-
for i in tb
|
154
|
-
print "\tfrom %s\n", i
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
protect :at_catchpoint
|
159
|
-
|
160
|
-
def at_tracing(context, file, line)
|
161
|
-
return if defined?(Debugger::RDEBUG_FILE) &&
|
162
|
-
Debugger::RDEBUG_FILE == file # Don't trace ourself
|
163
|
-
@last_file = CommandProcessor.canonic_file(file)
|
164
|
-
file = CommandProcessor.canonic_file(file)
|
165
|
-
unless file == @last_file and @last_line == line and
|
166
|
-
Command.settings[:tracing_plus]
|
167
|
-
print "Tracing(%d):%s:%s %s",
|
168
|
-
context.thnum, file, line, Debugger.line_at(file, line)
|
169
|
-
@last_file = file
|
170
|
-
@last_line = line
|
171
|
-
end
|
172
|
-
always_run(context, file, line, 2)
|
173
|
-
end
|
174
|
-
protect :at_tracing
|
175
|
-
|
176
|
-
def at_line(context, file, line)
|
177
|
-
process_commands(context, file, line)
|
178
|
-
end
|
179
|
-
protect :at_line
|
180
|
-
|
181
|
-
def at_return(context, file, line)
|
182
|
-
context.stop_frame = -1
|
183
|
-
process_commands(context, file, line)
|
184
|
-
end
|
185
|
-
|
186
|
-
def one_cmd(commands, context, input)
|
187
|
-
if cmd = commands.find{ |c| c.match(input) }
|
188
|
-
if context.dead? && cmd.class.need_context
|
189
|
-
p cmd
|
190
|
-
print "Command is unavailable\n"
|
191
|
-
else
|
192
|
-
cmd.execute
|
193
|
-
end
|
194
|
-
else
|
195
|
-
unknown_cmd = commands.find{|cmd| cmd.class.unknown }
|
196
|
-
if unknown_cmd
|
197
|
-
unknown_cmd.execute
|
198
|
-
else
|
199
|
-
errmsg "Unknown command: \"#{input}\". Try \"help\".\n"
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
private
|
205
|
-
|
206
|
-
# The prompt shown before reading a command.
|
207
|
-
def prompt(context)
|
208
|
-
p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum)
|
209
|
-
p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
|
210
|
-
Debugger.annotate.to_i > 2
|
211
|
-
return p
|
212
|
-
end
|
213
|
-
|
214
|
-
# Run these commands, for example display commands or possibly
|
215
|
-
# the list or irb in an "autolist" or "autoirb".
|
216
|
-
# We return a list of commands that are acceptable to run bound
|
217
|
-
# to the current state.
|
218
|
-
def always_run(context, file, line, run_level)
|
219
|
-
event_cmds = Command.commands.select{|cmd| cmd.event }
|
220
|
-
|
221
|
-
# Remove some commands in post-mortem
|
222
|
-
event_cmds = event_cmds.find_all do |cmd|
|
223
|
-
cmd.allow_in_post_mortem
|
224
|
-
end if context.dead?
|
225
|
-
|
226
|
-
state = State.new(self) do |s|
|
227
|
-
s.context = context
|
228
|
-
s.file = file
|
229
|
-
s.line = line
|
230
|
-
s.binding = context.frame_binding(0)
|
231
|
-
s.display = display
|
232
|
-
s.interface = interface
|
233
|
-
s.commands = event_cmds
|
234
|
-
end
|
235
|
-
@interface.state = state if @interface.respond_to?('state=')
|
236
|
-
|
237
|
-
# Bind commands to the current state.
|
238
|
-
commands = event_cmds.map{|cmd| cmd.new(state)}
|
239
|
-
|
240
|
-
commands.select do |cmd|
|
241
|
-
cmd.class.always_run >= run_level
|
242
|
-
end.each {|cmd| cmd.execute}
|
243
|
-
return state, commands
|
244
|
-
end
|
245
|
-
|
246
|
-
# Handle debugger commands
|
247
|
-
def process_commands(context, file, line)
|
248
|
-
state, @commands = always_run(context, file, line, 1)
|
249
|
-
$rdebug_state = state if Command.settings[:debuggertesting]
|
250
|
-
splitter = lambda do |str|
|
251
|
-
str.split(/;/).inject([]) do |m, v|
|
252
|
-
if m.empty?
|
253
|
-
m << v
|
254
|
-
else
|
255
|
-
if m.last[-1] == ?\\
|
256
|
-
m.last[-1,1] = ''
|
257
|
-
m.last << ';' << v
|
258
|
-
else
|
259
|
-
m << v
|
260
|
-
end
|
261
|
-
end
|
262
|
-
m
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
preloop(@commands, context)
|
267
|
-
CommandProcessor.print_location_and_text(file, line)
|
268
|
-
while !state.proceed?
|
269
|
-
input = if @interface.command_queue.empty?
|
270
|
-
@interface.read_command(prompt(context))
|
271
|
-
else
|
272
|
-
@interface.command_queue.shift
|
273
|
-
end
|
274
|
-
break unless input
|
275
|
-
catch(:debug_error) do
|
276
|
-
if input == ""
|
277
|
-
next unless @last_cmd
|
278
|
-
input = @last_cmd
|
279
|
-
else
|
280
|
-
@last_cmd = input
|
281
|
-
end
|
282
|
-
splitter[input].each do |cmd|
|
283
|
-
one_cmd(@commands, context, cmd)
|
284
|
-
postcmd(@commands, context, cmd)
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
288
|
-
postloop(@commands, context)
|
289
|
-
exception = state.exception
|
290
|
-
@exception = nil
|
291
|
-
puts "raising exception #{state.exception}"
|
292
|
-
raise exception if exception
|
293
|
-
end # process_commands
|
294
|
-
|
295
|
-
def preloop(commands, context)
|
296
|
-
aprint('stopped') if Debugger.annotate.to_i > 2
|
297
|
-
if context.dead?
|
298
|
-
unless @debugger_context_was_dead
|
299
|
-
if Debugger.annotate.to_i > 2
|
300
|
-
aprint('exited')
|
301
|
-
print "The program finished.\n"
|
302
|
-
end
|
303
|
-
@debugger_context_was_dead = true
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
if Debugger.annotate.to_i > 2
|
308
|
-
# if we are here, the stack frames have changed outside the
|
309
|
-
# command loop (e.g. after a "continue" command), so we show
|
310
|
-
# the annotations again
|
311
|
-
breakpoint_annotations(commands, context)
|
312
|
-
display_annotations(commands, context)
|
313
|
-
annotation('stack', commands, context, "where")
|
314
|
-
annotation('variables', commands, context, "info variables") unless
|
315
|
-
context.dead?
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def postcmd(commands, context, cmd)
|
320
|
-
if Debugger.annotate.to_i > 0
|
321
|
-
cmd = @last_cmd unless cmd
|
322
|
-
breakpoint_annotations(commands, context) if
|
323
|
-
@@Show_breakpoints_postcmd.find{|pat| cmd =~ pat}
|
324
|
-
display_annotations(commands, context)
|
325
|
-
if @@Show_annotations_postcmd.find{|pat| cmd =~ pat}
|
326
|
-
annotation('stack', commands, context, "where") if
|
327
|
-
context.stack_size > 0
|
328
|
-
annotation('variables', commands, context, "info variables") unless
|
329
|
-
context.dead?
|
330
|
-
end
|
331
|
-
if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat}
|
332
|
-
aprint 'starting' if Debugger.annotate.to_i > 2
|
333
|
-
|
334
|
-
@debugger_context_was_dead = false
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
def postloop(commands, context)
|
340
|
-
end
|
341
|
-
|
342
|
-
def annotation(label, commands, context, cmd)
|
343
|
-
print afmt(label)
|
344
|
-
one_cmd(commands, context, cmd)
|
345
|
-
### FIXME ANNOTATE: the following line should be deleted
|
346
|
-
print "\032\032\n"
|
347
|
-
end
|
348
|
-
|
349
|
-
def breakpoint_annotations(commands, context)
|
350
|
-
unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty
|
351
|
-
annotation('breakpoints', commands, context, "info breakpoints")
|
352
|
-
@debugger_breakpoints_were_empty = Debugger.breakpoints.empty?
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
def display_annotations(commands, context)
|
357
|
-
return if display.empty?
|
358
|
-
# have_display = display.find{|d| d[0]}
|
359
|
-
# return unless have_display and @debugger_displays_were_empty
|
360
|
-
# @debugger_displays_were_empty = have_display
|
361
|
-
annotation('display', commands, context, "display")
|
362
|
-
end
|
363
|
-
|
364
|
-
class State # :nodoc:
|
365
|
-
attr_accessor :context, :file, :line, :binding
|
366
|
-
attr_accessor :frame_pos, :previous_line, :display
|
367
|
-
attr_accessor :interface, :commands, :processor
|
368
|
-
attr_accessor :exception
|
369
|
-
|
370
|
-
def initialize(processor=nil)
|
371
|
-
super()
|
372
|
-
@frame_pos = 0
|
373
|
-
@previous_line = nil
|
374
|
-
@proceed = false
|
375
|
-
@processor = processor
|
376
|
-
yield self
|
377
|
-
end
|
378
|
-
|
379
|
-
# FIXME: use delegate?
|
380
|
-
def errmsg(*args)
|
381
|
-
@interface.errmsg(*args)
|
382
|
-
end
|
383
|
-
|
384
|
-
def print(*args)
|
385
|
-
@interface.print(*args)
|
386
|
-
end
|
387
|
-
|
388
|
-
def confirm(*args)
|
389
|
-
@interface.confirm(*args)
|
390
|
-
end
|
391
|
-
|
392
|
-
def proceed?
|
393
|
-
@proceed
|
394
|
-
end
|
395
|
-
|
396
|
-
def proceed
|
397
|
-
@proceed = true
|
398
|
-
end
|
399
|
-
end
|
400
|
-
end
|
401
|
-
|
402
|
-
class ControlCommandProcessor < Processor # :nodoc:
|
403
|
-
def initialize(interface)
|
404
|
-
super()
|
405
|
-
@interface = interface
|
406
|
-
@debugger_context_was_dead = true # Assume we haven't started.
|
407
|
-
end
|
408
|
-
|
409
|
-
def process_commands(verbose=false)
|
410
|
-
control_cmds = Command.commands.select do |cmd|
|
411
|
-
cmd.allow_in_control
|
412
|
-
end
|
413
|
-
state = State.new(@interface, control_cmds)
|
414
|
-
@commands = control_cmds.map{|cmd| cmd.new(state) }
|
415
|
-
|
416
|
-
unless @debugger_context_was_dead
|
417
|
-
if Debugger.annotate.to_i > 2
|
418
|
-
aprint 'exited'
|
419
|
-
print "The program finished.\n"
|
420
|
-
end
|
421
|
-
@debugger_context_was_dead = true
|
422
|
-
end
|
423
|
-
|
424
|
-
while input = @interface.read_command(prompt(nil))
|
425
|
-
print "+#{input}" if verbose
|
426
|
-
catch(:debug_error) do
|
427
|
-
if cmd = @commands.find{|c| c.match(input) }
|
428
|
-
cmd.execute
|
429
|
-
else
|
430
|
-
errmsg "Unknown command\n"
|
431
|
-
end
|
432
|
-
end
|
433
|
-
end
|
434
|
-
rescue IOError, Errno::EPIPE
|
435
|
-
rescue Exception
|
436
|
-
print "INTERNAL ERROR!!! #{$!}\n" rescue nil
|
437
|
-
print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
|
438
|
-
ensure
|
439
|
-
@interface.close
|
440
|
-
end
|
441
|
-
|
442
|
-
# The prompt shown before reading a command.
|
443
|
-
# Note: have an unused 'context' parameter to match the local interface.
|
444
|
-
def prompt(context)
|
445
|
-
p = '(rdb:ctrl) '
|
446
|
-
p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
|
447
|
-
Debugger.annotate.to_i > 2
|
448
|
-
return p
|
449
|
-
end
|
450
|
-
|
451
|
-
class State # :nodoc:
|
452
|
-
attr_reader :commands, :interface
|
453
|
-
|
454
|
-
def initialize(interface, commands)
|
455
|
-
@interface = interface
|
456
|
-
@commands = commands
|
457
|
-
end
|
458
|
-
|
459
|
-
def proceed
|
460
|
-
end
|
461
|
-
|
462
|
-
def errmsg(*args)
|
463
|
-
@interface.print(*args)
|
464
|
-
end
|
465
|
-
|
466
|
-
def print(*args)
|
467
|
-
@interface.print(*args)
|
468
|
-
end
|
469
|
-
|
470
|
-
def confirm(*args)
|
471
|
-
'y'
|
472
|
-
end
|
473
|
-
|
474
|
-
def context
|
475
|
-
nil
|
476
|
-
end
|
477
|
-
|
478
|
-
def file
|
479
|
-
errmsg "No filename given.\n"
|
480
|
-
throw :debug_error
|
481
|
-
end
|
482
|
-
end # State
|
483
|
-
end
|
484
|
-
end
|