ruby-debug19 0.11.5

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 (39) hide show
  1. data/AUTHORS +9 -0
  2. data/LICENSE +23 -0
  3. data/bin/rdebug +415 -0
  4. data/cli/ruby-debug.rb +176 -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/kill.rb +51 -0
  21. data/cli/ruby-debug/commands/list.rb +94 -0
  22. data/cli/ruby-debug/commands/method.rb +84 -0
  23. data/cli/ruby-debug/commands/quit.rb +39 -0
  24. data/cli/ruby-debug/commands/reload.rb +40 -0
  25. data/cli/ruby-debug/commands/save.rb +90 -0
  26. data/cli/ruby-debug/commands/set.rb +237 -0
  27. data/cli/ruby-debug/commands/show.rb +253 -0
  28. data/cli/ruby-debug/commands/source.rb +36 -0
  29. data/cli/ruby-debug/commands/stepping.rb +81 -0
  30. data/cli/ruby-debug/commands/threads.rb +189 -0
  31. data/cli/ruby-debug/commands/tmate.rb +36 -0
  32. data/cli/ruby-debug/commands/trace.rb +57 -0
  33. data/cli/ruby-debug/commands/variables.rb +199 -0
  34. data/cli/ruby-debug/debugger.rb +5 -0
  35. data/cli/ruby-debug/helper.rb +69 -0
  36. data/cli/ruby-debug/interface.rb +232 -0
  37. data/cli/ruby-debug/processor.rb +474 -0
  38. data/rdbg.rb +33 -0
  39. metadata +122 -0
@@ -0,0 +1,176 @@
1
+ module Debugger
2
+ module EvalFunctions # :nodoc:
3
+ def run_with_binding
4
+ binding = @state.context ? get_binding : TOPLEVEL_BINDING
5
+ $__dbg_interface = @state.interface
6
+ eval(<<-EOC, binding)
7
+ __dbg_verbose_save=$VERBOSE; $VERBOSE=false
8
+ def dbg_print(*args)
9
+ $__dbg_interface.print(*args)
10
+ end
11
+ remove_method :puts if self.respond_to?(:puts) &&
12
+ defined?(remove_method)
13
+ def dbg_puts(*args)
14
+ $__dbg_interface.print(*args)
15
+ $__dbg_interface.print("\n")
16
+ end
17
+ $VERBOSE=__dbg_verbose_save
18
+ EOC
19
+ yield binding
20
+ ensure
21
+ $__dbg_interface = nil
22
+ end
23
+ end
24
+
25
+ class EvalCommand < Command # :nodoc:
26
+ self.allow_in_control = true
27
+
28
+ register_setting_get(:autoeval) do
29
+ EvalCommand.unknown
30
+ end
31
+ register_setting_set(:autoeval) do |value|
32
+ EvalCommand.unknown = value
33
+ end
34
+
35
+ def match(input)
36
+ @input = input
37
+ super
38
+ end
39
+
40
+ def regexp
41
+ /^\s*(p|e(?:val)?)\s+/
42
+ end
43
+
44
+ def execute
45
+ expr = @match ? @match.post_match : @input
46
+ run_with_binding do |b|
47
+ print "%s\n", debug_eval(expr, b).inspect
48
+ end
49
+ end
50
+
51
+ class << self
52
+ def help_command
53
+ %w|p eval|
54
+ end
55
+
56
+ def help(cmd)
57
+ if cmd == 'p'
58
+ %{
59
+ p expression\tevaluate expression and print its value
60
+ }
61
+ else
62
+ %{
63
+ e[val] expression\tevaluate expression and print its value,
64
+ \t\t\talias for p.
65
+ * NOTE - to turn on autoeval, use 'set autoeval'
66
+ }
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ class PPCommand < Command # :nodoc:
73
+ self.allow_in_control = true
74
+
75
+ def regexp
76
+ /^\s*pp\s+/
77
+ end
78
+
79
+ def execute
80
+ out = StringIO.new
81
+ run_with_binding do |b|
82
+ PP.pp(debug_eval(@match.post_match, b), out)
83
+ end
84
+ print out.string
85
+ rescue
86
+ out.puts $!.message
87
+ end
88
+
89
+ class << self
90
+ def help_command
91
+ 'pp'
92
+ end
93
+
94
+ def help(cmd)
95
+ %{
96
+ pp expression\tevaluate expression and pretty-print its value
97
+ }
98
+ end
99
+ end
100
+ end
101
+
102
+ class PutLCommand < Command # :nodoc:
103
+ self.allow_in_control = true
104
+
105
+ def regexp
106
+ /^\s*putl\s+/
107
+ end
108
+
109
+ def execute
110
+ out = StringIO.new
111
+ run_with_binding do |b|
112
+ vals = debug_eval(@match.post_match, b)
113
+ if vals.is_a?(Array)
114
+ vals = vals.map{|item| item.to_s}
115
+ print "%s\n", columnize(vals, self.class.settings[:width])
116
+ else
117
+ PP.pp(vals, out)
118
+ print out.string
119
+ end
120
+ end
121
+ rescue
122
+ out.puts $!.message
123
+ end
124
+
125
+ class << self
126
+ def help_command
127
+ 'putl'
128
+ end
129
+
130
+ def help(cmd)
131
+ %{
132
+ putl expression\t\tevaluate expression, an array, and columnize its value
133
+ }
134
+ end
135
+ end
136
+ end
137
+
138
+ class PSCommand < Command # :nodoc:
139
+ self.allow_in_control = true
140
+
141
+ include EvalFunctions
142
+
143
+ def regexp
144
+ /^\s*ps\s+/
145
+ end
146
+
147
+ def execute
148
+ out = StringIO.new
149
+ run_with_binding do |b|
150
+ vals = debug_eval(@match.post_match, b)
151
+ if vals.is_a?(Array)
152
+ vals = vals.map{|item| item.to_s}
153
+ print "%s\n", columnize(vals.sort!, self.class.settings[:width])
154
+ else
155
+ PP.pp(vals, out)
156
+ print out.string
157
+ end
158
+ end
159
+ rescue
160
+ out.puts $!.message
161
+ end
162
+
163
+ class << self
164
+ def help_command
165
+ 'ps'
166
+ end
167
+
168
+ def help(cmd)
169
+ %{
170
+ ps expression\tevaluate expression, an array, sort, and columnize its value
171
+ }
172
+ end
173
+ end
174
+ end
175
+
176
+ end
@@ -0,0 +1,42 @@
1
+ module Debugger
2
+ # Implements the debugger 'finish' command.
3
+ class FinishCommand < Command
4
+ self.allow_in_post_mortem = false
5
+ self.need_context = true
6
+
7
+ def regexp
8
+ /^\s*fin(?:ish)? (?:\s+(.*))?$/x
9
+ end
10
+
11
+ def execute
12
+ max_frame = @state.context.stack_size - @state.frame_pos
13
+ if !@match[1] or @match[1].empty?
14
+ frame_pos = @state.frame_pos
15
+ else
16
+ frame_pos = get_int(@match[1], "Finish", 0, max_frame-1, 0)
17
+ return nil unless frame_pos
18
+ end
19
+ @state.context.stop_frame = frame_pos
20
+ @state.frame_pos = 0
21
+ @state.proceed
22
+ end
23
+
24
+ class << self
25
+ def help_command
26
+ 'finish'
27
+ end
28
+
29
+ def help(cmd)
30
+ %{
31
+ fin[ish] [frame-number]\tExecute until selected stack frame returns.
32
+
33
+ If no frame number is given, we run until the currently selected frame
34
+ returns. The currently selected frame starts out the most-recent
35
+ frame or 0 if no frame positioning (e.g "up", "down" or "frame") has
36
+ been performed. If a frame number is given we run until that frame
37
+ returns.
38
+ }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,301 @@
1
+ module Debugger
2
+ # Mix-in module to assist in command parsing.
3
+ module FrameFunctions # :nodoc:
4
+ def adjust_frame(frame_pos, absolute, context=@state.context)
5
+ @state.frame_pos = 0 if context != @state.context
6
+ if absolute
7
+ if frame_pos < 0
8
+ abs_frame_pos = context.stack_size + frame_pos
9
+ else
10
+ abs_frame_pos = frame_pos
11
+ end
12
+ else
13
+ abs_frame_pos = @state.frame_pos + frame_pos
14
+ end
15
+
16
+ if abs_frame_pos >= context.stack_size then
17
+ errmsg "Adjusting would put us beyond the oldest (initial) frame.\n"
18
+ return
19
+ elsif abs_frame_pos < 0 then
20
+ errmsg "Adjusting would put us beyond the newest (innermost) frame.\n"
21
+ return
22
+ end
23
+ if @state.frame_pos != abs_frame_pos then
24
+ @state.previous_line = nil
25
+ @state.frame_pos = abs_frame_pos
26
+ end
27
+
28
+ @state.file = context.frame_file(@state.frame_pos)
29
+ @state.line = context.frame_line(@state.frame_pos)
30
+
31
+ print_frame(@state.frame_pos, true)
32
+ end
33
+
34
+ def get_frame_call(prefix, pos, context)
35
+ id = context.frame_method(pos)
36
+ klass = context.frame_class(pos)
37
+ call_str = ""
38
+ if id
39
+ args = context.frame_args(pos)
40
+ locals = context.frame_locals(pos)
41
+ if Command.settings[:callstyle] != :short && klass
42
+ if Command.settings[:callstyle] == :tracked
43
+ arg_info = context.frame_args_info(pos)
44
+ end
45
+ call_str << "#{klass}."
46
+ end
47
+ call_str << id.id2name
48
+ if args.any?
49
+ call_str << "("
50
+ args.each_with_index do |name, i|
51
+ case Command.settings[:callstyle]
52
+ when :short
53
+ call_str += "%s, " % [name]
54
+ when :last
55
+ klass = locals[name].class
56
+ if klass.inspect.size > 20+3
57
+ klass = klass.inspect[0..20]+"..."
58
+ end
59
+ call_str += "%s#%s, " % [name, klass]
60
+ when :tracked
61
+ if arg_info && arg_info.size > i
62
+ call_str += "#{name}: #{arg_info[i].inspect}, "
63
+ else
64
+ call_str += "%s, " % name
65
+ end
66
+ end
67
+ if call_str.size > self.class.settings[:width] - prefix.size
68
+ # Strip off trailing ', ' if any but add stuff for later trunc
69
+ call_str[-2..-1] = ",...XX"
70
+ break
71
+ end
72
+ end
73
+ call_str[-2..-1] = ")" # Strip off trailing ', ' if any
74
+ end
75
+ end
76
+ return call_str
77
+ end
78
+
79
+ def print_frame(pos, adjust = false, context=@state.context)
80
+ file = context.frame_file(pos)
81
+ line = context.frame_line(pos)
82
+ klass = context.frame_class(pos)
83
+
84
+ unless Command.settings[:full_path]
85
+ path_components = file.split(/[\\\/]/)
86
+ if path_components.size > 3
87
+ path_components[0...-3] = '...'
88
+ file = path_components.join(File::ALT_SEPARATOR || File::SEPARATOR)
89
+ end
90
+ end
91
+
92
+ frame_num = "#%d " % pos
93
+ call_str = get_frame_call(frame_num, pos, context)
94
+ file_line = "at line %s:%d\n" % [CommandProcessor.canonic_file(file), line]
95
+ print frame_num
96
+ unless call_str.empty?
97
+ print call_str
98
+ print ' '
99
+ if call_str.size + frame_num.size + file_line.size > self.class.settings[:width]
100
+ print "\n "
101
+ end
102
+ end
103
+ print file_line
104
+ if ENV['EMACS'] && adjust
105
+ fmt = (Debugger.annotate.to_i > 1 ?
106
+ "\032\032source %s:%d\n" : "\032\032%s:%d\n")
107
+ print fmt % [CommandProcessor.canonic_file(file), line]
108
+ end
109
+ end
110
+
111
+ # Check if call stack is truncated. This can happen if
112
+ # Debugger.start is not called low enough in the call stack. An
113
+ # array of additional callstack lines from caller is returned if
114
+ # definitely truncated, false if not, and nil if we don't know.
115
+ #
116
+ # We determine truncation based on a passed in sentinal set via
117
+ # caller which can be nil.
118
+ #
119
+ # First we see if we can find our position in caller. If so, then
120
+ # we compare context position to that in caller using sentinal
121
+ # as a place to start ignoring additional caller entries. sentinal
122
+ # is set by rdebug, but if it's not set, i.e. nil then additional
123
+ # entries are presumably ones that we haven't recorded in context
124
+ def truncated_callstack?(context, sentinal=nil, cs=caller)
125
+ recorded_size = context.stack_size
126
+ to_find_fl = "#{context.frame_file(0)}:#{context.frame_line(0)}"
127
+ top_discard = false
128
+ cs.each_with_index do |fl, i|
129
+ fl.gsub!(/in `.*'$/, '')
130
+ fl.gsub!(/:$/, '')
131
+ if fl == to_find_fl
132
+ top_discard = i
133
+ break
134
+ end
135
+ end
136
+ if top_discard
137
+ cs = cs[top_discard..-1]
138
+ return false unless cs
139
+ return cs unless sentinal
140
+ if cs.size > recorded_size+2 && cs[recorded_size+2] != sentinal
141
+ # caller seems to truncate recursive calls and we don't.
142
+ # See if we can find sentinal in the first 0..recorded_size+1 entries
143
+ return false if cs[0..recorded_size+1].any?{ |f| f==sentinal }
144
+ return cs
145
+ end
146
+ return false
147
+ end
148
+ return nil
149
+ end
150
+
151
+
152
+ end
153
+
154
+ # Implements debugger "where" or "backtrace" command.
155
+ class WhereCommand < Command
156
+ def regexp
157
+ /^\s*(?:w(?:here)?|bt|backtrace)$/
158
+ end
159
+
160
+ def execute
161
+ (0...@state.context.stack_size).each do |idx|
162
+ if idx == @state.frame_pos
163
+ print "--> "
164
+ else
165
+ print " "
166
+ end
167
+ print_frame(idx)
168
+
169
+ end
170
+ if truncated_callstack?(@state.context, Debugger.start_sentinal)
171
+ print "Warning: saved frames may be incomplete; compare with caller(0).\n"
172
+ end
173
+ end
174
+
175
+ class << self
176
+ def help_command
177
+ %w|where backtrace|
178
+ end
179
+
180
+ def help(cmd)
181
+ s = if cmd == 'where'
182
+ %{
183
+ w[here]\tdisplay stack frames
184
+ }
185
+ else
186
+ %{
187
+ bt|backtrace\t\talias for where - display stack frames
188
+ }
189
+ end
190
+ s += %{
191
+ Print the entire stack frame. Each frame is numbered, the most recent
192
+ frame is 0. frame number can be referred to in the "frame" command;
193
+ "up" and "down" add or subtract respectively to frame numbers shown.
194
+ The position of the current frame is marked with -->. }
195
+ end
196
+ end
197
+ end
198
+
199
+ class UpCommand < Command # :nodoc:
200
+ def regexp
201
+ /^\s* u(?:p)? (?:\s+(.*))?$/x
202
+ end
203
+
204
+ def execute
205
+ pos = get_int(@match[1], "Up")
206
+ return unless pos
207
+ adjust_frame(pos, false)
208
+ end
209
+
210
+ class << self
211
+ def help_command
212
+ 'up'
213
+ end
214
+
215
+ def help(cmd)
216
+ %{
217
+ up[count]\tmove to higher frame
218
+ }
219
+ end
220
+ end
221
+ end
222
+
223
+ class DownCommand < Command # :nodoc:
224
+ def regexp
225
+ /^\s* down (?:\s+(.*))? .*$/x
226
+ end
227
+
228
+ def execute
229
+ pos = get_int(@match[1], "Down")
230
+ return unless pos
231
+ adjust_frame(-pos, false)
232
+ end
233
+
234
+ class << self
235
+ def help_command
236
+ 'down'
237
+ end
238
+
239
+ def help(cmd)
240
+ %{
241
+ down[count]\tmove to lower frame
242
+ }
243
+ end
244
+ end
245
+ end
246
+
247
+ class FrameCommand < Command # :nodoc:
248
+ def regexp
249
+ / ^\s*
250
+ f(?:rame)?
251
+ (?: \s+ (\S+))? \s*
252
+ (?: thread \s+ (.*))? \s*
253
+ $/x
254
+ end
255
+
256
+ def execute
257
+ if not @match[1]
258
+ pos = 0
259
+ else
260
+ pos = get_int(@match[1], "Frame")
261
+ return unless pos
262
+ end
263
+ if @match[2]
264
+ context = parse_thread_num('frame', @match[2])
265
+ unless context
266
+ errmsg "Thread #{@match[2]} doesn't exist.\n"
267
+ return
268
+ end
269
+ else
270
+ context = @state.context
271
+ end
272
+ adjust_frame(pos, true, context)
273
+ end
274
+
275
+ class << self
276
+ def help_command
277
+ 'frame'
278
+ end
279
+
280
+ def help(cmd)
281
+ %{
282
+ f[rame] [frame-number [thread thread-number]]
283
+ Move the current frame to the specified frame number, or the
284
+ 0 if no frame-number has been given.
285
+
286
+ A negative number indicates position from the other end. So
287
+ 'frame -1' moves to the oldest frame, and 'frame 0' moves to
288
+ the newest frame.
289
+
290
+ Without an argument, the command prints the current stack
291
+ frame. Since the current position is redisplayed, it may trigger a
292
+ resyncronization if there is a front end also watching over
293
+ things.
294
+
295
+ If a thread number is given then we set the context for evaluating
296
+ expressions to that frame of that thread.
297
+ }
298
+ end
299
+ end
300
+ end
301
+ end