ruby-debug 0.10.3 → 0.10.4

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 (108) hide show
  1. data/CHANGES +15 -0
  2. data/ChangeLog +461 -104
  3. data/Rakefile +69 -13
  4. data/VERSION +3 -0
  5. data/bin/rdebug +2 -1
  6. data/cli/ruby-debug.rb +8 -5
  7. data/cli/ruby-debug/command.rb +43 -4
  8. data/cli/ruby-debug/commands/breakpoints.rb +3 -1
  9. data/cli/ruby-debug/commands/catchpoint.rb +5 -3
  10. data/cli/ruby-debug/commands/{continue.RB.save → continue.RB} +0 -0
  11. data/cli/ruby-debug/commands/eval.rb +4 -1
  12. data/cli/ruby-debug/commands/frame.rb +11 -10
  13. data/cli/ruby-debug/commands/help.rb +5 -0
  14. data/cli/ruby-debug/commands/info.rb +6 -3
  15. data/cli/ruby-debug/commands/irb.rb +115 -12
  16. data/cli/ruby-debug/commands/kill.rb +50 -0
  17. data/cli/ruby-debug/commands/list.rb +3 -3
  18. data/cli/ruby-debug/commands/quit.rb +12 -6
  19. data/cli/ruby-debug/commands/raise.RB +41 -0
  20. data/cli/ruby-debug/commands/show.rb +26 -28
  21. data/cli/ruby-debug/helper.rb +5 -0
  22. data/cli/ruby-debug/interface.rb +53 -25
  23. data/cli/ruby-debug/processor.RB +484 -0
  24. data/cli/ruby-debug/processor.rb +140 -56
  25. data/rdbg.rb +0 -0
  26. data/runner.sh +7 -0
  27. data/test/base/base.rb +0 -0
  28. data/test/base/binding.rb +0 -0
  29. data/test/base/catchpoint.rb +0 -0
  30. data/test/base/reload_bug.rb +8 -0
  31. data/test/brkpt-class-bug.rb +8 -0
  32. data/test/cli/commands/unit/regexp.rb +11 -0
  33. data/test/config.yaml +8 -0
  34. data/test/data/annotate.cmd +1 -1
  35. data/test/data/annotate.right +3 -3
  36. data/test/data/break_bad.cmd +1 -1
  37. data/test/data/break_bad.right +1 -1
  38. data/test/data/break_loop_bug.right +1 -1
  39. data/test/data/breakpoints.cmd +1 -1
  40. data/test/data/breakpoints.right +3 -3
  41. data/test/data/brkpt-class-bug.cmd +9 -0
  42. data/test/data/brkpt-class-bug.right +18 -0
  43. data/test/data/catch.right +2 -0
  44. data/test/data/condition.cmd +1 -0
  45. data/test/data/condition.right +5 -3
  46. data/test/data/ctrl.right +2 -2
  47. data/test/data/display.right +1 -1
  48. data/test/data/emacs_basic.right +2 -2
  49. data/test/data/except-bug1.cmd +7 -0
  50. data/test/data/except-bug1.right +13 -0
  51. data/test/data/file-with-space.cmd +7 -0
  52. data/test/data/file-with-space.right +9 -0
  53. data/test/data/finish.right +1 -1
  54. data/test/data/frame.cmd +7 -1
  55. data/test/data/frame.right +12 -1
  56. data/test/data/info-var.right +1 -1
  57. data/test/data/info.cmd +1 -0
  58. data/test/data/info.right +21 -2
  59. data/test/data/list.right +1 -1
  60. data/test/data/method.right +1 -1
  61. data/test/data/post-mortem.right +5 -4
  62. data/test/data/save.right +1 -1
  63. data/test/data/setshow.cmd +0 -10
  64. data/test/data/setshow.right +0 -17
  65. data/test/dollar-0.rb +0 -0
  66. data/test/except-bug1.rb +4 -0
  67. data/test/file with space.rb +1 -0
  68. data/test/gcd-dbg.rb +0 -0
  69. data/test/helper.rb +7 -1
  70. data/test/pm-base.rb +0 -0
  71. data/test/pm.rb +1 -1
  72. data/test/raise.rb +0 -0
  73. data/test/rdebug-save.1 +7 -0
  74. data/test/tdebug.rb +2 -2
  75. data/test/test-annotate.rb +0 -0
  76. data/test/test-break-bad.rb +0 -0
  77. data/test/test-breakpoints.rb +0 -0
  78. data/test/test-brkpt-class-bug.rb +26 -0
  79. data/test/test-catch.rb +1 -1
  80. data/test/test-condition.rb +1 -1
  81. data/test/test-ctrl.rb +1 -0
  82. data/test/test-display.rb +0 -0
  83. data/test/test-dollar-0.rb +0 -0
  84. data/test/test-edit.rb +0 -0
  85. data/test/test-emacs-basic.rb +0 -0
  86. data/test/test-enable.rb +0 -0
  87. data/test/test-except-bug1.rb +31 -0
  88. data/test/test-file-with-space.rb +30 -0
  89. data/test/test-finish.rb +0 -0
  90. data/test/test-frame.rb +0 -0
  91. data/test/test-help.rb +0 -0
  92. data/test/test-hist.rb +0 -0
  93. data/test/test-info-thread.rb +0 -0
  94. data/test/test-info-var.rb +0 -0
  95. data/test/test-info.rb +0 -0
  96. data/test/test-init.rb +7 -1
  97. data/test/test-list.rb +0 -0
  98. data/test/test-method.rb +0 -0
  99. data/test/test-output.rb +0 -0
  100. data/test/test-pm.rb +0 -0
  101. data/test/test-quit.rb +0 -0
  102. data/test/test-raise.rb +1 -1
  103. data/test/test-save.rb +7 -1
  104. data/test/test-setshow.rb +0 -0
  105. data/test/test-source.rb +0 -0
  106. data/test/test-stepping.rb +0 -0
  107. data/test/test-trace.rb +0 -0
  108. metadata +211 -180
@@ -1,26 +1,38 @@
1
1
  require 'ruby-debug/interface'
2
2
  require 'ruby-debug/command'
3
3
 
4
+ # _Debugger_ is the module name space for ruby-debug.
4
5
  module Debugger
5
6
 
6
- # Should this be a mixin?
7
- class Processor # :nodoc
7
+ # A processor handles the kind of front-end to program interaction.
8
+ # Debugger::Processor is the the base class with subclasses
9
+ # Debugger::CommandProcessor and Debugger::ControlCommandProcessor.
10
+ class Processor
8
11
  attr_accessor :interface
12
+ attr_reader :processor
13
+ attr_reader :commands
9
14
 
10
- # Format msg with gdb-style annotation header
15
+ # Format _msg_ with gdb-style annotation header.
11
16
  def afmt(msg, newline="\n")
12
17
  "\032\032#{msg}#{newline}"
13
18
  end
14
19
 
20
+ # Print "annotation" message _msg_. Annotation messages are used
21
+ # by the GNU-Emacs front-end to get status about stacks and
22
+ # the state of the debugger without having to poll it for information
15
23
  def aprint(msg)
16
24
  print afmt(msg) if Debugger.annotate.to_i > 2
17
25
  end
18
26
 
19
- # FIXME: use delegate?
27
+ # Print a debugger error message; _args_ should be compatible
28
+ # with something you would pass to Kernel::print.
20
29
  def errmsg(*args)
21
30
  @interface.errmsg(*args)
22
31
  end
23
32
 
33
+ # Print a normal debugger message; _args_ should be compatible
34
+ # with something you would pass to Kernel::print.
35
+ #
24
36
  # Callers of this routine should make sure to use comma to
25
37
  # separate format argments rather than %. Otherwise it seems that
26
38
  # if the string you want to print has format specifier, which
@@ -33,7 +45,10 @@ module Debugger
33
45
 
34
46
  end
35
47
 
36
- class CommandProcessor < Processor # :nodoc:
48
+ # A Debugger::CommandProcessor is the kind of Debugger::Processor
49
+ # used when you are running inside the same process as the debugged
50
+ # program.
51
+ class CommandProcessor < Processor
37
52
  attr_reader :display
38
53
 
39
54
  # FIXME: get from Command regexp method.
@@ -60,7 +75,8 @@ module Debugger
60
75
 
61
76
  def initialize(interface = LocalInterface.new)
62
77
  @interface = interface
63
- @display = []
78
+ @commands = []
79
+ @display = []
64
80
 
65
81
  @mutex = Mutex.new
66
82
  @last_cmd = nil
@@ -80,7 +96,7 @@ module Debugger
80
96
 
81
97
  require 'pathname' # For cleanpath
82
98
 
83
- # Regularize file name.
99
+ # Regularize or "canonicalize" file name _filename_.
84
100
  # This is also used as a common funnel place if basename is
85
101
  # desired or if we are working remotely and want to change the
86
102
  # basename. Or we are eliding filenames.
@@ -100,12 +116,15 @@ module Debugger
100
116
  # FIXME: use annotations routines
101
117
  if Debugger.annotate.to_i > 2
102
118
  file_line = "\032\032source #{file_line}"
103
- elsif ENV['EMACS']
119
+ elsif Debugger.inside_emacs?
104
120
  file_line = "\032\032#{file_line}"
105
121
  end
106
122
  print file_line
107
123
  end
108
-
124
+
125
+ # Create a "protected" version of method _mname_. A protected
126
+ # method handles all unhandled exceptions that would cause the
127
+ # program to terminate.
109
128
  def self.protect(mname)
110
129
  alias_method "__#{mname}", mname
111
130
  module_eval %{
@@ -116,13 +135,17 @@ module Debugger
116
135
  end
117
136
  rescue IOError, Errno::EPIPE
118
137
  self.interface = nil
138
+ rescue SignalException
139
+ raise
119
140
  rescue Exception
120
141
  print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
121
142
  print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
122
143
  end
123
144
  }
124
145
  end
125
-
146
+
147
+ # This is a callback routine when the debugged program hits a
148
+ # breakpoint event. For example ruby-debug-base calls this.
126
149
  def at_breakpoint(context, breakpoint)
127
150
  aprint 'stopped' if Debugger.annotate.to_i > 2
128
151
  n = Debugger.breakpoints.index(breakpoint) + 1
@@ -135,11 +158,13 @@ module Debugger
135
158
  end
136
159
  protect :at_breakpoint
137
160
 
161
+ # This is a callback routine when the debugged program hits a
162
+ # catchpoint. For example ruby-debug-base calls this.
138
163
  def at_catchpoint(context, excpt)
139
164
  aprint 'stopped' if Debugger.annotate.to_i > 2
140
165
  file = CommandProcessor.canonic_file(context.frame_file(0))
141
166
  line = context.frame_line(0)
142
- print afmt("%s:%d" % [file, line]) if ENV['EMACS']
167
+ print afmt("%s:%d" % [file, line]) if Debugger.inside_emacs?
143
168
  print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class
144
169
  fs = context.stack_size
145
170
  tb = caller(0)[-fs..-1]
@@ -167,19 +192,52 @@ module Debugger
167
192
  end
168
193
  protect :at_tracing
169
194
 
195
+ # This is a callback routine when the debugged program hits a
196
+ # "line" (or statement boundary) event. For example
197
+ # ruby-debug-base calls this.
170
198
  def at_line(context, file, line)
171
199
  process_commands(context, file, line)
172
200
  end
173
201
  protect :at_line
174
202
 
203
+ # This is a callback routine when the debugged program hits a
204
+ # "return" event. For example ruby-debug-base calls this.
205
+ # Note: right now ruby-debug-base does not call this. Perhaps
206
+ # other bases routines such as the one in JRuby do.
175
207
  def at_return(context, file, line)
176
208
  context.stop_frame = -1
177
209
  process_commands(context, file, line)
178
210
  end
211
+
212
+ # Return the command object to run given input string _input_.
213
+ def lookup(input)
214
+ @commands.find{ |c| c.match(input) }
215
+ end
216
+
217
+ # Run a single command specified by string _input_; _commands_ is and
218
+ # Array of possible debugger command objects and _context_ is
219
+ # a Debugger::Context object.
220
+ def one_cmd(commands, context, input)
221
+ if cmd = lookup(input)
222
+ if context.dead? && cmd.class.need_context
223
+ p cmd
224
+ print "Command is unavailable\n"
225
+ else
226
+ cmd.execute
227
+ end
228
+ else
229
+ unknown_cmd = commands.find{|cmd| cmd.class.unknown }
230
+ if unknown_cmd
231
+ unknown_cmd.execute
232
+ else
233
+ errmsg "Unknown command: \"#{input}\". Try \"help\".\n"
234
+ end
235
+ end
236
+ end
179
237
 
180
238
  private
181
239
 
182
- # The prompt shown before reading a command.
240
+ # Return a prompt string to show before reading a command.
183
241
  def prompt(context)
184
242
  p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum)
185
243
  p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
@@ -187,19 +245,19 @@ module Debugger
187
245
  return p
188
246
  end
189
247
 
190
- # Run these commands, for example display commands or possibly
191
- # the list or irb in an "autolist" or "autoirb".
192
- # We return a list of commands that are acceptable to run bound
193
- # to the current state.
248
+ # Run commands that we always have to run before a entering a
249
+ # command loop. For example commands registered via debugger "set
250
+ # display", "set autolist", or set "autoirb". We return a list of
251
+ # commands that are acceptable to run bound to the current state.
194
252
  def always_run(context, file, line, run_level)
195
253
  event_cmds = Command.commands.select{|cmd| cmd.event }
196
254
 
197
- # Remove some commands in post-mortem
255
+ # Remove some commands if we are post mortem.
198
256
  event_cmds = event_cmds.find_all do |cmd|
199
257
  cmd.allow_in_post_mortem
200
258
  end if context.dead?
201
259
 
202
- state = State.new do |s|
260
+ state = State.new(self) do |s|
203
261
  s.context = context
204
262
  s.file = file
205
263
  s.line = line
@@ -219,10 +277,12 @@ module Debugger
219
277
  return state, commands
220
278
  end
221
279
 
222
- # Handle debugger commands
280
+ # This the main debugger command-line loop. Here we read a
281
+ # debugger command, perform it, and ask for another one unless we
282
+ # are told to continue execution or terminate.
223
283
  def process_commands(context, file, line)
224
- state, commands = always_run(context, file, line, 1)
225
-
284
+ state, @commands = always_run(context, file, line, 1)
285
+ $rdebug_state = state if Command.settings[:debuggertesting]
226
286
  splitter = lambda do |str|
227
287
  str.split(/;/).inject([]) do |m, v|
228
288
  if m.empty?
@@ -239,7 +299,7 @@ module Debugger
239
299
  end
240
300
  end
241
301
 
242
- preloop(commands, context)
302
+ preloop(@commands, context)
243
303
  CommandProcessor.print_location_and_text(file, line)
244
304
  while !state.proceed?
245
305
  input = if @interface.command_queue.empty?
@@ -256,32 +316,18 @@ module Debugger
256
316
  @last_cmd = input
257
317
  end
258
318
  splitter[input].each do |cmd|
259
- one_cmd(commands, context, cmd)
260
- postcmd(commands, context, cmd)
319
+ one_cmd(@commands, context, cmd)
320
+ postcmd(@commands, context, cmd)
261
321
  end
262
322
  end
263
323
  end
264
- postloop(commands, context)
324
+ postloop(@commands, context)
265
325
  end # process_commands
266
-
267
- def one_cmd(commands, context, input)
268
- if cmd = commands.find{ |c| c.match(input) }
269
- if context.dead? && cmd.class.need_context
270
- p cmd
271
- print "Command is unavailable\n"
272
- else
273
- cmd.execute
274
- end
275
- else
276
- unknown_cmd = commands.find{|cmd| cmd.class.unknown }
277
- if unknown_cmd
278
- unknown_cmd.execute
279
- else
280
- errmsg "Unknown command: \"#{input}\". Try \"help\".\n"
281
- end
282
- end
283
- end
284
-
326
+
327
+ # Things we do before entering the debugger command loop.
328
+ # Note: in the trepanning debuggers this and always_run have been
329
+ # merged. To do this and get the order right we add a priority level
330
+ # for each hook.
285
331
  def preloop(commands, context)
286
332
  aprint('stopped') if Debugger.annotate.to_i > 2
287
333
  if context.dead?
@@ -306,6 +352,7 @@ module Debugger
306
352
  end
307
353
  end
308
354
 
355
+ # Things we do after leaving the debugger command loop.
309
356
  def postcmd(commands, context, cmd)
310
357
  if Debugger.annotate.to_i > 0
311
358
  cmd = @last_cmd unless cmd
@@ -326,9 +373,14 @@ module Debugger
326
373
  end
327
374
  end
328
375
 
376
+ # Things we do after leaving the debugger command loop.
329
377
  def postloop(commands, context)
330
378
  end
331
379
 
380
+ # Run a command in String _cmd_, but tag output with annotation
381
+ # specified in String _label+. +commands_ is an Array of all
382
+ # possible debugger command objects, and _context_ is a
383
+ # Debugger::Context object.
332
384
  def annotation(label, commands, context, cmd)
333
385
  print afmt(label)
334
386
  one_cmd(commands, context, cmd)
@@ -354,25 +406,37 @@ module Debugger
354
406
  class State # :nodoc:
355
407
  attr_accessor :context, :file, :line, :binding
356
408
  attr_accessor :frame_pos, :previous_line, :display
357
- attr_accessor :interface, :commands
409
+ attr_accessor :interface, :commands, :processor
358
410
 
359
- def initialize
411
+ def initialize(processor=nil)
360
412
  super()
361
- @frame_pos = 0
413
+ @frame_pos = 0
362
414
  @previous_line = nil
363
- @proceed = false
415
+ @proceed = false
416
+ @processor = processor
364
417
  yield self
365
418
  end
366
419
 
367
- # FIXME: use delegate?
420
+ # Print a debugger error message; _args_ should be compatible
421
+ # with something you would pass to Kernel::print.
368
422
  def errmsg(*args)
369
423
  @interface.errmsg(*args)
370
424
  end
371
425
 
426
+ # Print a normal debugger message; _args_ should be compatible
427
+ # with something you would pass to Kernel::print.
428
+ #
429
+ # Callers of this routine should make sure to use comma to
430
+ # separate format argments rather than %. Otherwise it seems that
431
+ # if the string you want to print has format specifier, which
432
+ # could happen if you are trying to show say a source-code line
433
+ # with "puts" or "print" in it, this print routine will give an
434
+ # error saying it is looking for more arguments.
372
435
  def print(*args)
373
436
  @interface.print(*args)
374
437
  end
375
438
 
439
+ # confirm is called before performing a dangerous action.
376
440
  def confirm(*args)
377
441
  @interface.confirm(*args)
378
442
  end
@@ -387,19 +451,25 @@ module Debugger
387
451
  end
388
452
  end
389
453
 
390
- class ControlCommandProcessor < Processor # :nodoc:
454
+ # A Debugger::ControlCommandProcessor is the kind of Debugger::Processor
455
+ # used the debugged program is running remotely. It is also entered
456
+ # after the debugged program has terminated.
457
+ class ControlCommandProcessor < Processor
391
458
  def initialize(interface)
392
459
  super()
393
460
  @interface = interface
394
461
  @debugger_context_was_dead = true # Assume we haven't started.
395
462
  end
396
-
463
+
464
+ # This the main debugger command-line loop. Here we read a
465
+ # debugger command, perform it, and ask for another one unless we
466
+ # are told to continue execution or terminate.
397
467
  def process_commands(verbose=false)
398
468
  control_cmds = Command.commands.select do |cmd|
399
469
  cmd.allow_in_control
400
470
  end
401
471
  state = State.new(@interface, control_cmds)
402
- commands = control_cmds.map{|cmd| cmd.new(state) }
472
+ @commands = control_cmds.map{|cmd| cmd.new(state) }
403
473
 
404
474
  unless @debugger_context_was_dead
405
475
  if Debugger.annotate.to_i > 2
@@ -412,7 +482,7 @@ module Debugger
412
482
  while input = @interface.read_command(prompt(nil))
413
483
  print "+#{input}" if verbose
414
484
  catch(:debug_error) do
415
- if cmd = commands.find{|c| c.match(input) }
485
+ if cmd = @commands.find{|c| c.match(input) }
416
486
  cmd.execute
417
487
  else
418
488
  errmsg "Unknown command\n"
@@ -427,8 +497,9 @@ module Debugger
427
497
  @interface.close
428
498
  end
429
499
 
430
- # The prompt shown before reading a command.
431
- # Note: have an unused 'context' parameter to match the local interface.
500
+ # Return a prompt string to show before reading a command. Note: The
501
+ # _context_ parameter is not used. It must be provided so that the
502
+ # interface matches Debugger::CommandProcessor#prompt.
432
503
  def prompt(context)
433
504
  p = '(rdb:ctrl) '
434
505
  p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
@@ -447,14 +518,27 @@ module Debugger
447
518
  def proceed
448
519
  end
449
520
 
521
+ # Print a debugger error message; _args_ should be compatible
522
+ # with something you would pass to Kernel::print.
450
523
  def errmsg(*args)
451
524
  @interface.print(*args)
452
525
  end
453
526
 
527
+ # Print a normal debugger message; _args_ should be compatible
528
+ # with something you would pass to Kernel::print.
529
+ #
530
+ # Callers of this routine should make sure to use comma to
531
+ # separate format argments rather than %. Otherwise it seems that
532
+ # if the string you want to print has format specifier, which
533
+ # could happen if you are trying to show say a source-code line
534
+ # with "puts" or "print" in it, this print routine will give an
535
+ # error saying it is looking for more arguments.
454
536
  def print(*args)
455
537
  @interface.print(*args)
456
538
  end
457
-
539
+
540
+ # confirm is called before performing a dangerous action. In
541
+ # control processor we always return "yes" or "y".
458
542
  def confirm(*args)
459
543
  'y'
460
544
  end
data/rdbg.rb CHANGED
File without changes
data/runner.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby=${RUBY:-ruby}
4
+ dir=`dirname $0`
5
+ rdebug=${RDEBUG:-${dir}/bin/rdebug}
6
+ $ruby -I${dir}/ext:${dir}/lib:${dir}/cli -- $rdebug $*
7
+ exit $?
data/test/base/base.rb CHANGED
File without changes
data/test/base/binding.rb CHANGED
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ class TestReloadBug < Test::Unit::TestCase
4
+ def test_reload_bug
5
+ top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
6
+ assert_equal({}, Debugger::source_reload)
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class A
2
+ def A.show
3
+ puts "hi"
4
+ end
5
+ end
6
+ x = 1
7
+ A.show
8
+ y = 2
@@ -9,6 +9,17 @@ class TestCommandREs < Test::Unit::TestCase
9
9
  require File.join(base_dir, 'commands', 'frame')
10
10
  include Debugger
11
11
 
12
+ def test_quit
13
+ c = QuitCommand.new(nil)
14
+ assert c.regexp.match('quit')
15
+ assert c.regexp.match('q')
16
+ assert c.regexp.match('quit!')
17
+ assert c.regexp.match('q!')
18
+ assert c.regexp.match('quit unconditionally')
19
+ assert c.regexp.match('exit')
20
+ assert c.regexp.match('exit!')
21
+ end
22
+
12
23
  def test_up
13
24
  c = UpCommand.new(nil)
14
25
  assert c.regexp.match('up')