ruby-debug 0.10.2 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
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