ruby-debug 0.10.2 → 0.10.3

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 (69) hide show
  1. data/CHANGES +13 -0
  2. data/ChangeLog +307 -0
  3. data/README +15 -7
  4. data/Rakefile +7 -3
  5. data/bin/rdebug +106 -28
  6. data/cli/ruby-debug.rb +31 -2
  7. data/cli/ruby-debug/commands/breakpoints.rb +4 -0
  8. data/cli/ruby-debug/commands/continue.RB.save +48 -0
  9. data/cli/ruby-debug/commands/disassemble.RB +38 -0
  10. data/cli/ruby-debug/commands/frame.rb +46 -0
  11. data/cli/ruby-debug/commands/source.RB +44 -0
  12. data/cli/ruby-debug/interface.rb +1 -1
  13. data/rdbg.rb +0 -0
  14. data/test/base/base.rb +0 -0
  15. data/test/base/binding.rb +0 -0
  16. data/test/base/catchpoint.rb +0 -0
  17. data/test/cli/commands/catchpoint_test.rb +9 -8
  18. data/test/cli/commands/unit/regexp.rb +31 -0
  19. data/test/data/annotate.right +2 -0
  20. data/test/data/breakpoints.right +11 -7
  21. data/test/data/emacs_basic.right +7 -2
  22. data/test/data/finish.right +0 -12
  23. data/test/data/pm-bug.cmd +7 -0
  24. data/test/data/pm-bug.right +12 -0
  25. data/test/data/post-mortem.right +4 -4
  26. data/test/data/raise.right +3 -3
  27. data/test/dollar-0.rb +0 -0
  28. data/test/except-bug2.rb +7 -0
  29. data/test/gcd-dbg.rb +0 -0
  30. data/test/helper.rb +5 -1
  31. data/test/pm-base.rb +0 -0
  32. data/test/pm-bug.rb +3 -0
  33. data/test/pm.rb +0 -0
  34. data/test/raise.rb +0 -0
  35. data/test/scope-test.rb +8 -0
  36. data/test/tdebug.rb +10 -1
  37. data/test/test-annotate.rb +0 -0
  38. data/test/test-break-bad.rb +0 -0
  39. data/test/test-breakpoints.rb +0 -0
  40. data/test/test-catch.rb +0 -0
  41. data/test/test-condition.rb +0 -0
  42. data/test/test-ctrl.rb +0 -0
  43. data/test/test-display.rb +0 -0
  44. data/test/test-dollar-0.rb +9 -3
  45. data/test/test-edit.rb +0 -0
  46. data/test/test-emacs-basic.rb +0 -0
  47. data/test/test-enable.rb +0 -0
  48. data/test/test-finish.rb +7 -7
  49. data/test/test-frame.rb +1 -1
  50. data/test/test-help.rb +0 -0
  51. data/test/test-hist.rb +0 -0
  52. data/test/test-info-thread.rb +0 -0
  53. data/test/test-info-var.rb +0 -0
  54. data/test/test-info.rb +0 -0
  55. data/test/test-init.rb +0 -0
  56. data/test/test-list.rb +0 -0
  57. data/test/test-method.rb +0 -0
  58. data/test/test-output.rb +0 -0
  59. data/test/test-pm.rb +13 -0
  60. data/test/test-quit.rb +0 -0
  61. data/test/test-raise.rb +0 -0
  62. data/test/test-save.rb +0 -0
  63. data/test/test-setshow.rb +0 -0
  64. data/test/test-source.rb +0 -0
  65. data/test/test-stepping.rb +0 -0
  66. data/test/test-trace.rb +0 -0
  67. data/test/trunc-call.rb +31 -0
  68. data/test/tvar.rb +3 -0
  69. metadata +179 -177
data/cli/ruby-debug.rb CHANGED
@@ -25,9 +25,15 @@ module Debugger
25
25
  end
26
26
 
27
27
  class << self
28
+ # gdb-style annotation mode. Used in GNU Emacs interface
29
+ attr_accessor :annotate
30
+
28
31
  # in remote mode, wait for the remote connection
29
32
  attr_accessor :wait_connection
30
- attr_accessor :annotate
33
+
34
+ # If set, a string to look for in caller() and is used to see
35
+ # if the call stack is truncated.
36
+ attr_accessor :start_sentinal
31
37
 
32
38
  attr_reader :thread, :control_thread
33
39
 
@@ -80,7 +86,7 @@ module Debugger
80
86
 
81
87
  def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc:
82
88
  raise "Debugger is not started" unless started?
83
- return if @control_thread
89
+ return if defined?(@control_thread) && @control_thread
84
90
  @control_thread = DebugThread.new do
85
91
  server = TCPServer.new(host, ctrl_port)
86
92
  while (session = server.accept)
@@ -145,3 +151,26 @@ module Debugger
145
151
  end
146
152
  end
147
153
  end
154
+
155
+ module Kernel
156
+
157
+ # Enters the debugger in the current thread after _steps_ line events occur.
158
+ # Before entering the debugger startup script is read.
159
+ #
160
+ # Setting _steps_ to 0 will cause a break in the debugger subroutine
161
+ # and not wait for a line event to occur. You will have to go "up 1"
162
+ # in order to be back in your debugged program rather than the
163
+ # debugger. Settings _steps_ to 0 could be useful you want to stop
164
+ # right after the last statement in some scope, because the next
165
+ # step will take you out of some scope.
166
+ def debugger(steps = 1)
167
+ Debugger.start unless Debugger.started?
168
+ Debugger.run_init_script(StringIO.new)
169
+ if 0 == steps
170
+ Debugger.current_context.stop_frame = 0
171
+ else
172
+ Debugger.current_context.stop_next = steps
173
+ end
174
+ end
175
+ alias breakpoint debugger unless respond_to?(:breakpoint)
176
+ end
@@ -72,7 +72,11 @@ module Debugger
72
72
  errmsg("Line %d is not a stopping point in file \"%s\".\n", line, file)
73
73
  return
74
74
  end
75
+ else
76
+ errmsg("No source file named %s\n" % file)
77
+ return unless confirm("Set breakpoint anyway? (y/n) ")
75
78
  end
79
+
76
80
  unless @state.context
77
81
  errmsg "We are not in a state we can add breakpoints.\n"
78
82
  return
@@ -0,0 +1,48 @@
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
@@ -0,0 +1,38 @@
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
@@ -107,6 +107,48 @@ module Debugger
107
107
  print fmt % [CommandProcessor.canonic_file(file), line]
108
108
  end
109
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
+
110
152
  end
111
153
 
112
154
  # Implements debugger "where" or "backtrace" command.
@@ -123,6 +165,10 @@ module Debugger
123
165
  print " "
124
166
  end
125
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"
126
172
  end
127
173
  end
128
174
 
@@ -0,0 +1,44 @@
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
@@ -83,7 +83,7 @@ module Debugger
83
83
  end
84
84
  end
85
85
 
86
- def readline_support?(msg)
86
+ def readline_support?
87
87
  @have_readline
88
88
  end
89
89
 
data/rdbg.rb CHANGED
File without changes
data/test/base/base.rb CHANGED
File without changes
data/test/base/binding.rb CHANGED
File without changes
File without changes
@@ -2,16 +2,17 @@
2
2
 
3
3
  require 'test/unit'
4
4
 
5
- BASE_DIR = File.join(File.dirname(__FILE__), '..', '..', '..')
6
-
7
- %w(ext lib cli).each do |dir|
8
- $: << File.join(BASE_DIR, dir)
9
- end
10
-
11
- require File.join(BASE_DIR, 'cli', 'ruby-debug')
12
-
13
5
  class TestCatchCommand < Test::Unit::TestCase
14
6
 
7
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__),
8
+ '..', '..', '..'))
9
+
10
+ %w(ext lib cli).each do |dir|
11
+ $: << File.join(base_dir, dir)
12
+ end
13
+
14
+ require File.join(base_dir, 'cli', 'ruby-debug')
15
+
15
16
  class MockState
16
17
  attr_accessor :message
17
18
  def context; end
@@ -0,0 +1,31 @@
1
+ require 'test/unit'
2
+
3
+
4
+ class TestCommandREs < Test::Unit::TestCase
5
+ base_dir=File.expand_path(File.join(File.dirname(__FILE__),
6
+ '..', '..', '..', '..',
7
+ 'cli', 'ruby-debug'))
8
+ require File.join(base_dir, 'command')
9
+ require File.join(base_dir, 'commands', 'frame')
10
+ include Debugger
11
+
12
+ def test_up
13
+ c = UpCommand.new(nil)
14
+ assert c.regexp.match('up')
15
+ assert c.regexp.match('up 2')
16
+ assert c.regexp.match('up 2+5')
17
+ assert c.regexp.match('u')
18
+ assert c.regexp.match('u 2')
19
+ assert_equal nil, c.regexp.match('ufoo')
20
+ end
21
+
22
+ def test_down
23
+ c = DownCommand.new(nil)
24
+ assert c.regexp.match('down')
25
+ assert c.regexp.match('down 2')
26
+ assert_equal(nil, c.regexp.match('d 2'))
27
+ assert_equal(nil, c.regexp.match('d'))
28
+ assert_equal(nil, c.regexp.match('dow'))
29
+ end
30
+ end
31
+
@@ -128,9 +128,11 @@ self = main
128
128
  error-begin
129
129
  No source file named bogus
130
130
  
131
+ Breakpoint 3 file bogus, line 5
131
132
  breakpoints
132
133
  Num Enb What
133
134
  2 y at gcd.rb:12
135
+ 3 y at bogus:5
134
136
  
135
137
  display
136
138
  
@@ -42,16 +42,17 @@ return nil if a <= 0
42
42
  # info program
43
43
  Program stopped. It stopped at a breakpoint.
44
44
  # c 6
45
- Breakpoint 2 at gcd.rb:10
46
- gcd.rb:10
47
- return nil if a <= 0
45
+ Breakpoint 3 at Object:gcd
46
+ gcd.rb:4
47
+ def gcd(a, b)
48
48
  # info break
49
49
  Num Enb What
50
50
  1 y at gcd.rb:6
51
51
  breakpoint already hit 1 time
52
52
  2 y at gcd.rb:10
53
- breakpoint already hit 2 times
53
+ breakpoint already hit 1 time
54
54
  3 y at Object:gcd
55
+ breakpoint already hit 1 time
55
56
  # break foo
56
57
  *** Invalid breakpoint location: foo.
57
58
  # info break
@@ -59,23 +60,26 @@ Num Enb What
59
60
  1 y at gcd.rb:6
60
61
  breakpoint already hit 1 time
61
62
  2 y at gcd.rb:10
62
- breakpoint already hit 2 times
63
+ breakpoint already hit 1 time
63
64
  3 y at Object:gcd
65
+ breakpoint already hit 1 time
64
66
  # disable 1
65
67
  # info break
66
68
  Num Enb What
67
69
  1 n at gcd.rb:6
68
70
  breakpoint already hit 1 time
69
71
  2 y at gcd.rb:10
70
- breakpoint already hit 2 times
72
+ breakpoint already hit 1 time
71
73
  3 y at Object:gcd
74
+ breakpoint already hit 1 time
72
75
  # delete 1
73
76
  # # We should see breakpoint 2 but not 1
74
77
  # info break
75
78
  Num Enb What
76
79
  2 y at gcd.rb:10
77
- breakpoint already hit 2 times
80
+ breakpoint already hit 1 time
78
81
  3 y at Object:gcd
82
+ breakpoint already hit 1 time
79
83
  # # We should still be able to access 2
80
84
  # disable 2
81
85
  # disable bar
@@ -42,8 +42,9 @@ return nil if a <= 0
42
42
  # info program
43
43
  Program stopped. It stopped at a breakpoint.
44
44
  # c 10
45
- gcd.rb:10
46
- return nil if a <= 0
45
+ Breakpoint 3 at Object:gcd
46
+ gcd.rb:4
47
+ def gcd(a, b)
47
48
  # info break
48
49
  Num Enb What
49
50
  1 y at gcd.rb:6
@@ -51,6 +52,7 @@ Num Enb What
51
52
  2 y at gcd.rb:10
52
53
  breakpoint already hit 1 time
53
54
  3 y at Object:gcd
55
+ breakpoint already hit 1 time
54
56
  # break foo
55
57
  *** Invalid breakpoint location: foo.
56
58
  # info break
@@ -60,6 +62,7 @@ Num Enb What
60
62
  2 y at gcd.rb:10
61
63
  breakpoint already hit 1 time
62
64
  3 y at Object:gcd
65
+ breakpoint already hit 1 time
63
66
  # disable 1
64
67
  # info break
65
68
  Num Enb What
@@ -68,6 +71,7 @@ Num Enb What
68
71
  2 y at gcd.rb:10
69
72
  breakpoint already hit 1 time
70
73
  3 y at Object:gcd
74
+ breakpoint already hit 1 time
71
75
  # enable breakpoint 1
72
76
  # enable br 10
73
77
  Enable breakpoints argument '10' needs to at most 3.
@@ -78,6 +82,7 @@ Num Enb What
78
82
  2 y at gcd.rb:10
79
83
  breakpoint already hit 1 time
80
84
  3 y at Object:gcd
85
+ breakpoint already hit 1 time
81
86
  # # We should still be able to access 2
82
87
  # disable 2
83
88
  # enable