ruby-debug193 0.0.1

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.
Files changed (40) hide show
  1. data/AUTHORS +10 -0
  2. data/LICENSE +23 -0
  3. data/bin/rdebug +398 -0
  4. data/cli/ruby-debug.rb +173 -0
  5. data/cli/ruby-debug/command.rb +228 -0
  6. data/cli/ruby-debug/commands/breakpoints.rb +153 -0
  7. data/cli/ruby-debug/commands/catchpoint.rb +55 -0
  8. data/cli/ruby-debug/commands/condition.rb +49 -0
  9. data/cli/ruby-debug/commands/continue.rb +38 -0
  10. data/cli/ruby-debug/commands/control.rb +107 -0
  11. data/cli/ruby-debug/commands/display.rb +120 -0
  12. data/cli/ruby-debug/commands/edit.rb +48 -0
  13. data/cli/ruby-debug/commands/enable.rb +202 -0
  14. data/cli/ruby-debug/commands/eval.rb +176 -0
  15. data/cli/ruby-debug/commands/finish.rb +42 -0
  16. data/cli/ruby-debug/commands/frame.rb +301 -0
  17. data/cli/ruby-debug/commands/help.rb +56 -0
  18. data/cli/ruby-debug/commands/info.rb +469 -0
  19. data/cli/ruby-debug/commands/irb.rb +123 -0
  20. data/cli/ruby-debug/commands/jump.rb +66 -0
  21. data/cli/ruby-debug/commands/kill.rb +51 -0
  22. data/cli/ruby-debug/commands/list.rb +94 -0
  23. data/cli/ruby-debug/commands/method.rb +84 -0
  24. data/cli/ruby-debug/commands/quit.rb +39 -0
  25. data/cli/ruby-debug/commands/reload.rb +40 -0
  26. data/cli/ruby-debug/commands/save.rb +90 -0
  27. data/cli/ruby-debug/commands/set.rb +237 -0
  28. data/cli/ruby-debug/commands/show.rb +253 -0
  29. data/cli/ruby-debug/commands/source.rb +36 -0
  30. data/cli/ruby-debug/commands/stepping.rb +81 -0
  31. data/cli/ruby-debug/commands/threads.rb +189 -0
  32. data/cli/ruby-debug/commands/tmate.rb +36 -0
  33. data/cli/ruby-debug/commands/trace.rb +57 -0
  34. data/cli/ruby-debug/commands/variables.rb +199 -0
  35. data/cli/ruby-debug/debugger.rb +5 -0
  36. data/cli/ruby-debug/helper.rb +69 -0
  37. data/cli/ruby-debug/interface.rb +232 -0
  38. data/cli/ruby-debug/processor.rb +474 -0
  39. data/rdbg.rb +33 -0
  40. metadata +144 -0
@@ -0,0 +1,228 @@
1
+ require 'rubygems'
2
+ require 'columnize'
3
+ require_relative 'helper'
4
+
5
+ module Debugger
6
+ RUBY_DEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless
7
+ defined?(RUBY_DEBUG_DIR)
8
+
9
+ class Command # :nodoc:
10
+ SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
11
+ defined?(SubcmdStruct)
12
+
13
+ include Columnize
14
+
15
+ # Find param in subcmds. param id downcased and can be abbreviated
16
+ # to the minimum length listed in the subcommands
17
+ def find(subcmds, param)
18
+ param.downcase!
19
+ for try_subcmd in subcmds do
20
+ if (param.size >= try_subcmd.min) and
21
+ (try_subcmd.name[0..param.size-1] == param)
22
+ return try_subcmd
23
+ end
24
+ end
25
+ return nil
26
+ end
27
+
28
+ class << self
29
+ def commands
30
+ @commands ||= []
31
+ end
32
+
33
+ DEF_OPTIONS = {
34
+ :allow_in_control => false,
35
+ :allow_in_post_mortem => true,
36
+ :event => true,
37
+ :always_run => 0,
38
+ :unknown => false,
39
+ :need_context => false,
40
+ } unless defined?(DEF_OPTIONS)
41
+
42
+ def inherited(klass)
43
+ DEF_OPTIONS.each do |o, v|
44
+ klass.options[o] = v if klass.options[o].nil?
45
+ end
46
+ commands << klass
47
+ end
48
+
49
+ def load_commands
50
+ Dir[File.join(Debugger.const_get(:RUBY_DEBUG_DIR), 'commands', '*')].each do |file|
51
+ require file if file =~ /\.rb$/
52
+ end
53
+ Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
54
+ include mod
55
+ end
56
+ end
57
+
58
+ def method_missing(meth, *args, &block)
59
+ if meth.to_s =~ /^(.+?)=$/
60
+ @options[$1.intern] = args.first
61
+ else
62
+ if @options.has_key?(meth)
63
+ @options[meth]
64
+ else
65
+ super
66
+ end
67
+ end
68
+ end
69
+
70
+ def options
71
+ @options ||= {}
72
+ end
73
+
74
+ def settings_map
75
+ @@settings_map ||= {}
76
+ end
77
+ private :settings_map
78
+
79
+ def settings
80
+ unless true and defined? @settings and @settings
81
+ @settings = Object.new
82
+ map = settings_map
83
+ c = class << @settings; self end
84
+ if c.respond_to?(:funcall)
85
+ c.funcall(:define_method, :[]) do |name|
86
+ raise "No such setting #{name}" unless map.has_key?(name)
87
+ map[name][:getter].call
88
+ end
89
+ else
90
+ c.send(:define_method, :[]) do |name|
91
+ raise "No such setting #{name}" unless map.has_key?(name)
92
+ map[name][:getter].call
93
+ end
94
+ end
95
+ c = class << @settings; self end
96
+ if c.respond_to?(:funcall)
97
+ c.funcall(:define_method, :[]=) do |name, value|
98
+ raise "No such setting #{name}" unless map.has_key?(name)
99
+ map[name][:setter].call(value)
100
+ end
101
+ else
102
+ c.send(:define_method, :[]=) do |name, value|
103
+ raise "No such setting #{name}" unless map.has_key?(name)
104
+ map[name][:setter].call(value)
105
+ end
106
+ end
107
+ end
108
+ @settings
109
+ end
110
+
111
+ def register_setting_var(name, default)
112
+ var_name = "@@#{name}"
113
+ class_variable_set(var_name, default)
114
+ register_setting_get(name) { class_variable_get(var_name) }
115
+ register_setting_set(name) { |value| class_variable_set(var_name, value) }
116
+ end
117
+
118
+ def register_setting_get(name, &block)
119
+ settings_map[name] ||= {}
120
+ settings_map[name][:getter] = block
121
+ end
122
+
123
+ def register_setting_set(name, &block)
124
+ settings_map[name] ||= {}
125
+ settings_map[name][:setter] = block
126
+ end
127
+ end
128
+
129
+ register_setting_var(:basename, false) # use basename in showing files?
130
+ register_setting_var(:callstyle, :last)
131
+ register_setting_var(:debuggertesting, false)
132
+ register_setting_var(:force_stepping, false)
133
+ register_setting_var(:full_path, true)
134
+ register_setting_var(:listsize, 10) # number of lines in list command
135
+ register_setting_var(:stack_trace_on_error, false)
136
+ register_setting_var(:tracing_plus, false) # different linetrace lines?
137
+
138
+ # width of line output. Use COLUMNS value if it exists and is
139
+ # not too rediculously large.
140
+ width = ENV['COLUMNS'].to_i
141
+ width = 80 unless width > 10
142
+ register_setting_var(:width, width)
143
+
144
+ if not defined? Debugger::ARGV
145
+ Debugger::ARGV = ARGV.clone
146
+ end
147
+ register_setting_var(:argv, Debugger::ARGV)
148
+
149
+ def initialize(state)
150
+ @state = state
151
+ end
152
+
153
+ def match(input)
154
+ @match = regexp.match(input)
155
+ end
156
+
157
+ protected
158
+
159
+ # FIXME: use delegate?
160
+ def errmsg(*args)
161
+ @state.errmsg(*args)
162
+ end
163
+
164
+ def print(*args)
165
+ @state.print(*args)
166
+ end
167
+
168
+ def confirm(msg)
169
+ @state.confirm(msg) == 'y'
170
+ end
171
+
172
+ def debug_eval(str, b = get_binding)
173
+ begin
174
+ val = eval(str, b)
175
+ rescue StandardError, ScriptError => e
176
+ if Command.settings[:stack_trace_on_error]
177
+ at = eval("caller(1)", b)
178
+ print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
179
+ for i in at
180
+ print "\tfrom %s\n", i
181
+ end
182
+ else
183
+ print "#{e.class} Exception: #{e.message}\n"
184
+ end
185
+ throw :debug_error
186
+ end
187
+ end
188
+
189
+ def debug_silent_eval(str)
190
+ begin
191
+ eval(str, get_binding)
192
+ rescue StandardError, ScriptError
193
+ nil
194
+ end
195
+ end
196
+
197
+ def get_binding
198
+ @state.context.frame_binding(@state.frame_pos)
199
+ end
200
+
201
+ def line_at(file, line)
202
+ Debugger.line_at(file, line)
203
+ end
204
+
205
+ def get_context(thnum)
206
+ Debugger.contexts.find{|c| c.thnum == thnum}
207
+ end
208
+ end
209
+
210
+ Command.load_commands
211
+
212
+ # Returns setting object.
213
+ # Use Debugger.settings[] and Debugger.settings[]= methods to query and set
214
+ # debugger settings. These settings are available:
215
+ #
216
+ # - :autolist - automatically calls 'list' command on breakpoint
217
+ # - :autoeval - evaluates input in the current binding if it's not recognized as a debugger command
218
+ # - :autoirb - automatically calls 'irb' command on breakpoint
219
+ # - :stack_trace_on_error - shows full stack trace if eval command results with an exception
220
+ # - :frame_full_path - displays full paths when showing frame stack
221
+ # - :frame_class_names - displays method's class name when showing frame stack
222
+ # - :reload_source_on_change - makes 'list' command to always display up-to-date source code
223
+ # - :force_stepping - stepping command asways move to the new line
224
+ #
225
+ def self.settings
226
+ Command.settings
227
+ end
228
+ end
@@ -0,0 +1,153 @@
1
+ module Debugger
2
+
3
+ # Implements debugger "break" command.
4
+ class AddBreakpoint < Command
5
+ self.allow_in_control = true
6
+
7
+ def regexp
8
+ / ^\s*
9
+ b(?:reak)?
10
+ (?: \s+ #{Position_regexp})? \s*
11
+ (?: \s+ (.*))? \s*
12
+ $
13
+ /x
14
+ end
15
+
16
+ def execute
17
+ if @match[1]
18
+ line, _, _, expr = @match.captures
19
+ else
20
+ _, file, line, expr = @match.captures
21
+ end
22
+ if expr
23
+ if expr !~ /^\s*if\s+(.+)/
24
+ if file or line
25
+ errmsg "Expecting 'if' in breakpoint condition; got: #{expr}.\n"
26
+ else
27
+ errmsg "Invalid breakpoint location: #{expr}.\n"
28
+ end
29
+ return
30
+ else
31
+ expr = $1
32
+ end
33
+ end
34
+
35
+ brkpt_filename = nil
36
+ if file.nil?
37
+ unless @state.context
38
+ errmsg "We are not in a state that has an associated file.\n"
39
+ return
40
+ end
41
+ brkpt_filename = @state.file
42
+ file = File.basename(@state.file)
43
+ if line.nil?
44
+ # Set breakpoint at current line
45
+ line = @state.line.to_s
46
+ end
47
+ elsif line !~ /^\d+$/
48
+ # See if "line" is a method/function name
49
+ klass = debug_silent_eval(file)
50
+ if klass && klass.kind_of?(Module)
51
+ class_name = klass.name if klass
52
+ else
53
+ errmsg "Unknown class #{file}.\n"
54
+ throw :debug_error
55
+ end
56
+ else
57
+ # FIXME: This should be done in LineCache.
58
+ file = File.expand_path(file) if file.index(File::SEPARATOR) || \
59
+ File::ALT_SEPARATOR && file.index(File::ALT_SEPARATOR)
60
+ brkpt_filename = file
61
+ end
62
+
63
+ if line =~ /^\d+$/
64
+ line = line.to_i
65
+ if LineCache.cache(brkpt_filename, Command.settings[:reload_source_on_change])
66
+ last_line = LineCache.size(brkpt_filename)
67
+ if line > last_line
68
+ errmsg("There are only %d lines in file \"%s\".\n", last_line, file)
69
+ return
70
+ end
71
+ unless LineCache.trace_line_numbers(brkpt_filename).member?(line)
72
+ errmsg("Line %d is not a stopping point in file \"%s\".\n", line, file)
73
+ return
74
+ end
75
+ else
76
+ errmsg("No source file named %s\n" % file)
77
+ return unless confirm("Set breakpoint anyway? (y/n) ")
78
+ end
79
+
80
+ unless @state.context
81
+ errmsg "We are not in a state we can add breakpoints.\n"
82
+ return
83
+ end
84
+ b = Debugger.add_breakpoint brkpt_filename, line, expr
85
+ print "Breakpoint %d file %s, line %s\n", b.id, brkpt_filename, line.to_s
86
+ unless syntax_valid?(expr)
87
+ errmsg("Expression \"#{expr}\" syntactically incorrect; breakpoint disabled.\n")
88
+ b.enabled = false
89
+ end
90
+ else
91
+ method = line.intern.id2name
92
+ b = Debugger.add_breakpoint class_name, method, expr
93
+ print "Breakpoint %d at %s::%s\n", b.id, class_name, method.to_s
94
+ end
95
+ end
96
+
97
+ class << self
98
+ def help_command
99
+ 'break'
100
+ end
101
+
102
+ def help(cmd)
103
+ %{
104
+ b[reak] file:line [if expr]
105
+ b[reak] class(.|#)method [if expr]
106
+ \tset breakpoint to some position, (optionally) if expr == true
107
+ }
108
+ end
109
+ end
110
+ end
111
+
112
+ # Implements debugger "delete" command.
113
+ class DeleteBreakpointCommand < Command
114
+ self.allow_in_control = true
115
+
116
+ def regexp
117
+ /^\s *del(?:ete)? (?:\s+(.*))?$/ix
118
+ end
119
+
120
+ def execute
121
+ unless @state.context
122
+ errmsg "We are not in a state we can delete breakpoints.\n"
123
+ return
124
+ end
125
+ brkpts = @match[1]
126
+ unless brkpts
127
+ if confirm("Delete all breakpoints? (y or n) ")
128
+ Debugger.breakpoints.clear
129
+ end
130
+ else
131
+ brkpts.split(/[ \t]+/).each do |pos|
132
+ pos = get_int(pos, "Delete", 1)
133
+ return unless pos
134
+ unless Debugger.remove_breakpoint(pos)
135
+ errmsg "No breakpoint number %d\n", pos
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ class << self
142
+ def help_command
143
+ 'delete'
144
+ end
145
+
146
+ def help(cmd)
147
+ %{
148
+ del[ete][ nnn...]\tdelete some or all breakpoints
149
+ }
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,55 @@
1
+ module Debugger
2
+ class CatchCommand < Command # :nodoc:
3
+ self.allow_in_control = true
4
+
5
+ def regexp
6
+ /^\s* cat(?:ch)?
7
+ (?:\s+ (\S+))?
8
+ (?:\s+ (off))? \s* $/ix
9
+ end
10
+
11
+ def execute
12
+ excn = @match[1]
13
+ if not excn
14
+ # No args given.
15
+ info_catch
16
+ elsif not @match[2]
17
+ # One arg given.
18
+ if 'off' == excn
19
+ Debugger.catchpoints.clear if
20
+ confirm("Delete all catchpoints? (y or n) ")
21
+ else
22
+ binding = @state.context ? get_binding : TOPLEVEL_BINDING
23
+ unless debug_eval("#{excn}.is_a?(Class)", binding)
24
+ print "Warning #{excn} is not known to be a Class\n"
25
+ end
26
+ Debugger.add_catchpoint(excn)
27
+ print "Catch exception %s.\n", excn
28
+ end
29
+ elsif @match[2] != 'off'
30
+ errmsg "Off expected. Got %s\n", @match[2]
31
+ elsif Debugger.catchpoints.member?(excn)
32
+ Debugger.catchpoints.delete(excn)
33
+ print "Catch for exception %s removed.\n", excn
34
+ else
35
+ errmsg "Catch for exception %s not found.\n", excn
36
+ end
37
+ end
38
+
39
+ class << self
40
+ def help_command
41
+ 'catch'
42
+ end
43
+
44
+ def help(cmd)
45
+ %{
46
+ cat[ch]\t\tsame as "info catch"
47
+ cat[ch] <exception-name> [on|off]
48
+ \tIntercept <exception-name> when there would otherwise be no handler.
49
+ \tWith an "on" or "off", turn handling the exception on or off.
50
+ cat[ch] off\tdelete all catchpoints
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ module Debugger
2
+
3
+ class ConditionCommand < Command # :nodoc:
4
+
5
+ def regexp
6
+ /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix
7
+ end
8
+
9
+ def execute
10
+ if not @match[1]
11
+ errmsg "\"condition\" must be followed a breakpoint number and expression\n"
12
+ else
13
+ breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
14
+ largest = breakpoints.inject(0) do |largest, b|
15
+ largest = b.id if b.id > largest
16
+ end
17
+ if 0 == largest
18
+ print "No breakpoints have been set.\n"
19
+ return
20
+ end
21
+ pos = get_int(@match[1], "Condition", 1, largest)
22
+ return unless pos
23
+ breakpoints.each do |b|
24
+ if b.id == pos
25
+ b.expr = @match[2].empty? ? nil : @match[2]
26
+ break
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def help_command
35
+ 'condition'
36
+ end
37
+
38
+ def help(cmd)
39
+ %{
40
+ Condition breakpoint-number expression
41
+ Specify breakpoint number N to break only if COND is true.
42
+ N is an integer and COND is an expression to be evaluated whenever
43
+ breakpoint N is reached. If the empty string is used, the condition is removed.
44
+ }
45
+ end
46
+ end
47
+ end
48
+
49
+ end # module Debugger