debugger 1.0.0.rc1

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 (261) hide show
  1. data/AUTHORS +10 -0
  2. data/CHANGES +334 -0
  3. data/ChangeLog +5655 -0
  4. data/INSTALL.SVN +154 -0
  5. data/LICENSE +23 -0
  6. data/Makefile.am +14 -0
  7. data/OLD_README +122 -0
  8. data/README.md +10 -0
  9. data/Rakefile +266 -0
  10. data/autogen.sh +4 -0
  11. data/bin/rdebug +398 -0
  12. data/cli/ruby-debug.rb +173 -0
  13. data/cli/ruby-debug/command.rb +228 -0
  14. data/cli/ruby-debug/commands/breakpoints.rb +153 -0
  15. data/cli/ruby-debug/commands/catchpoint.rb +55 -0
  16. data/cli/ruby-debug/commands/condition.rb +49 -0
  17. data/cli/ruby-debug/commands/continue.rb +38 -0
  18. data/cli/ruby-debug/commands/control.rb +107 -0
  19. data/cli/ruby-debug/commands/display.rb +120 -0
  20. data/cli/ruby-debug/commands/edit.rb +48 -0
  21. data/cli/ruby-debug/commands/enable.rb +202 -0
  22. data/cli/ruby-debug/commands/eval.rb +176 -0
  23. data/cli/ruby-debug/commands/finish.rb +42 -0
  24. data/cli/ruby-debug/commands/frame.rb +301 -0
  25. data/cli/ruby-debug/commands/help.rb +56 -0
  26. data/cli/ruby-debug/commands/info.rb +467 -0
  27. data/cli/ruby-debug/commands/irb.rb +123 -0
  28. data/cli/ruby-debug/commands/jump.rb +66 -0
  29. data/cli/ruby-debug/commands/kill.rb +51 -0
  30. data/cli/ruby-debug/commands/list.rb +94 -0
  31. data/cli/ruby-debug/commands/method.rb +84 -0
  32. data/cli/ruby-debug/commands/quit.rb +39 -0
  33. data/cli/ruby-debug/commands/reload.rb +40 -0
  34. data/cli/ruby-debug/commands/save.rb +90 -0
  35. data/cli/ruby-debug/commands/set.rb +221 -0
  36. data/cli/ruby-debug/commands/show.rb +247 -0
  37. data/cli/ruby-debug/commands/skip.rb +35 -0
  38. data/cli/ruby-debug/commands/source.rb +36 -0
  39. data/cli/ruby-debug/commands/stepping.rb +81 -0
  40. data/cli/ruby-debug/commands/threads.rb +189 -0
  41. data/cli/ruby-debug/commands/tmate.rb +36 -0
  42. data/cli/ruby-debug/commands/trace.rb +57 -0
  43. data/cli/ruby-debug/commands/variables.rb +199 -0
  44. data/cli/ruby-debug/debugger.rb +5 -0
  45. data/cli/ruby-debug/helper.rb +69 -0
  46. data/cli/ruby-debug/interface.rb +232 -0
  47. data/cli/ruby-debug/processor.rb +474 -0
  48. data/configure.ac +12 -0
  49. data/debugger.gemspec +24 -0
  50. data/doc/.cvsignore +42 -0
  51. data/doc/Makefile.am +63 -0
  52. data/doc/emacs-notes.txt +38 -0
  53. data/doc/hanoi.rb +35 -0
  54. data/doc/primes.rb +28 -0
  55. data/doc/rdebug-emacs.texi +1030 -0
  56. data/doc/rdebug.1 +241 -0
  57. data/doc/ruby-debug.texi +3791 -0
  58. data/doc/test-tri2.rb +18 -0
  59. data/doc/tri3.rb +8 -0
  60. data/doc/triangle.rb +12 -0
  61. data/emacs/Makefile.am +130 -0
  62. data/emacs/rdebug-annotate.el +385 -0
  63. data/emacs/rdebug-breaks.el +407 -0
  64. data/emacs/rdebug-cmd.el +92 -0
  65. data/emacs/rdebug-core.el +502 -0
  66. data/emacs/rdebug-dbg.el +62 -0
  67. data/emacs/rdebug-error.el +79 -0
  68. data/emacs/rdebug-fns.el +111 -0
  69. data/emacs/rdebug-frames.el +230 -0
  70. data/emacs/rdebug-gud.el +242 -0
  71. data/emacs/rdebug-help.el +104 -0
  72. data/emacs/rdebug-info.el +83 -0
  73. data/emacs/rdebug-layouts.el +180 -0
  74. data/emacs/rdebug-locring.el +118 -0
  75. data/emacs/rdebug-output.el +106 -0
  76. data/emacs/rdebug-regexp.el +118 -0
  77. data/emacs/rdebug-secondary.el +260 -0
  78. data/emacs/rdebug-shortkey.el +175 -0
  79. data/emacs/rdebug-source.el +568 -0
  80. data/emacs/rdebug-track.el +392 -0
  81. data/emacs/rdebug-varbuf.el +150 -0
  82. data/emacs/rdebug-vars.el +125 -0
  83. data/emacs/rdebug-watch.el +132 -0
  84. data/emacs/rdebug.el +326 -0
  85. data/emacs/test/elk-test.el +242 -0
  86. data/emacs/test/test-annotate.el +103 -0
  87. data/emacs/test/test-cmd.el +116 -0
  88. data/emacs/test/test-core.el +104 -0
  89. data/emacs/test/test-fns.el +65 -0
  90. data/emacs/test/test-frames.el +62 -0
  91. data/emacs/test/test-gud.el +35 -0
  92. data/emacs/test/test-indent.el +58 -0
  93. data/emacs/test/test-regexp.el +144 -0
  94. data/emacs/test/test-shortkey.el +61 -0
  95. data/ext/ruby_debug/breakpoint.c +586 -0
  96. data/ext/ruby_debug/extconf.rb +49 -0
  97. data/ext/ruby_debug/ruby_debug.c +2624 -0
  98. data/ext/ruby_debug/ruby_debug.h +148 -0
  99. data/lib/ChangeLog +1065 -0
  100. data/lib/debugger.rb +7 -0
  101. data/lib/debugger/version.rb +3 -0
  102. data/lib/ruby-debug-base.rb +304 -0
  103. data/rdbg.rb +33 -0
  104. data/runner.sh +7 -0
  105. data/svn2cl_usermap +3 -0
  106. data/test/.cvsignore +1 -0
  107. data/test/base/base.rb +74 -0
  108. data/test/base/binding.rb +31 -0
  109. data/test/base/catchpoint.rb +26 -0
  110. data/test/base/load.rb +40 -0
  111. data/test/bp_loop_issue.rb +3 -0
  112. data/test/classes.rb +11 -0
  113. data/test/cli/commands/catchpoint_test.rb +36 -0
  114. data/test/cli/commands/unit/regexp.rb +42 -0
  115. data/test/config.yaml +8 -0
  116. data/test/data/annotate.cmd +29 -0
  117. data/test/data/annotate.right +139 -0
  118. data/test/data/break_bad.cmd +18 -0
  119. data/test/data/break_bad.right +28 -0
  120. data/test/data/break_loop_bug.cmd +5 -0
  121. data/test/data/break_loop_bug.right +15 -0
  122. data/test/data/breakpoints.cmd +38 -0
  123. data/test/data/breakpoints.right +98 -0
  124. data/test/data/catch.cmd +20 -0
  125. data/test/data/catch.right +49 -0
  126. data/test/data/catch2.cmd +19 -0
  127. data/test/data/catch2.right +65 -0
  128. data/test/data/catch3.cmd +11 -0
  129. data/test/data/catch3.right +37 -0
  130. data/test/data/condition.cmd +28 -0
  131. data/test/data/condition.right +65 -0
  132. data/test/data/ctrl.cmd +23 -0
  133. data/test/data/ctrl.right +70 -0
  134. data/test/data/display.cmd +24 -0
  135. data/test/data/display.right +44 -0
  136. data/test/data/dollar-0.right +2 -0
  137. data/test/data/dollar-0a.right +2 -0
  138. data/test/data/dollar-0b.right +2 -0
  139. data/test/data/edit.cmd +12 -0
  140. data/test/data/edit.right +19 -0
  141. data/test/data/emacs_basic.cmd +43 -0
  142. data/test/data/emacs_basic.right +106 -0
  143. data/test/data/enable.cmd +20 -0
  144. data/test/data/enable.right +36 -0
  145. data/test/data/finish.cmd +16 -0
  146. data/test/data/finish.right +31 -0
  147. data/test/data/frame.cmd +26 -0
  148. data/test/data/frame.right +55 -0
  149. data/test/data/help.cmd +20 -0
  150. data/test/data/help.right +21 -0
  151. data/test/data/history.right +7 -0
  152. data/test/data/info-thread.cmd +13 -0
  153. data/test/data/info-thread.right +37 -0
  154. data/test/data/info-var-bug2.cmd +5 -0
  155. data/test/data/info-var-bug2.right +10 -0
  156. data/test/data/info-var.cmd +23 -0
  157. data/test/data/info-var.right +52 -0
  158. data/test/data/info.cmd +21 -0
  159. data/test/data/info.right +65 -0
  160. data/test/data/jump.cmd +16 -0
  161. data/test/data/jump.right +56 -0
  162. data/test/data/jump2.cmd +16 -0
  163. data/test/data/jump2.right +44 -0
  164. data/test/data/linetrace.cmd +6 -0
  165. data/test/data/linetrace.right +23 -0
  166. data/test/data/list.cmd +19 -0
  167. data/test/data/list.right +127 -0
  168. data/test/data/method.cmd +10 -0
  169. data/test/data/method.right +21 -0
  170. data/test/data/methodsig.cmd +10 -0
  171. data/test/data/methodsig.right +20 -0
  172. data/test/data/next.cmd +22 -0
  173. data/test/data/next.right +61 -0
  174. data/test/data/noquit.right +1 -0
  175. data/test/data/output.cmd +6 -0
  176. data/test/data/output.right +31 -0
  177. data/test/data/pm-bug.cmd +7 -0
  178. data/test/data/pm-bug.right +12 -0
  179. data/test/data/post-mortem-next.cmd +8 -0
  180. data/test/data/post-mortem-next.right +14 -0
  181. data/test/data/post-mortem-osx.right +31 -0
  182. data/test/data/post-mortem.cmd +13 -0
  183. data/test/data/post-mortem.right +32 -0
  184. data/test/data/quit.cmd +6 -0
  185. data/test/data/quit.right +0 -0
  186. data/test/data/raise.cmd +11 -0
  187. data/test/data/raise.right +23 -0
  188. data/test/data/save.cmd +34 -0
  189. data/test/data/save.right +59 -0
  190. data/test/data/scope-var.cmd +42 -0
  191. data/test/data/scope-var.right +587 -0
  192. data/test/data/setshow.cmd +56 -0
  193. data/test/data/setshow.right +98 -0
  194. data/test/data/source.cmd +5 -0
  195. data/test/data/source.right +15 -0
  196. data/test/data/stepping.cmd +21 -0
  197. data/test/data/stepping.right +50 -0
  198. data/test/data/test-init-cygwin.right +7 -0
  199. data/test/data/test-init-osx.right +4 -0
  200. data/test/data/test-init.right +5 -0
  201. data/test/data/trace.right +14 -0
  202. data/test/dollar-0.rb +5 -0
  203. data/test/gcd-dbg-nox.rb +31 -0
  204. data/test/gcd-dbg.rb +30 -0
  205. data/test/gcd.rb +18 -0
  206. data/test/helper.rb +144 -0
  207. data/test/info-var-bug.rb +47 -0
  208. data/test/info-var-bug2.rb +2 -0
  209. data/test/jump.rb +14 -0
  210. data/test/jump2.rb +27 -0
  211. data/test/next.rb +18 -0
  212. data/test/null.rb +1 -0
  213. data/test/output.rb +2 -0
  214. data/test/pm-base.rb +22 -0
  215. data/test/pm-bug.rb +3 -0
  216. data/test/pm-catch.rb +12 -0
  217. data/test/pm-catch2.rb +27 -0
  218. data/test/pm-catch3.rb +47 -0
  219. data/test/pm.rb +11 -0
  220. data/test/raise.rb +3 -0
  221. data/test/rdebug-save.1 +7 -0
  222. data/test/runall +12 -0
  223. data/test/scope-var.rb +29 -0
  224. data/test/tdebug.rb +248 -0
  225. data/test/test-annotate.rb +25 -0
  226. data/test/test-break-bad.rb +37 -0
  227. data/test/test-breakpoints.rb +25 -0
  228. data/test/test-catch.rb +25 -0
  229. data/test/test-catch2.rb +25 -0
  230. data/test/test-catch3.rb +25 -0
  231. data/test/test-condition.rb +25 -0
  232. data/test/test-ctrl.rb +55 -0
  233. data/test/test-display.rb +26 -0
  234. data/test/test-dollar-0.rb +40 -0
  235. data/test/test-edit.rb +26 -0
  236. data/test/test-emacs-basic.rb +26 -0
  237. data/test/test-enable.rb +25 -0
  238. data/test/test-finish.rb +34 -0
  239. data/test/test-frame.rb +34 -0
  240. data/test/test-help.rb +60 -0
  241. data/test/test-hist.rb +68 -0
  242. data/test/test-info-thread.rb +32 -0
  243. data/test/test-info-var.rb +47 -0
  244. data/test/test-info.rb +26 -0
  245. data/test/test-init.rb +44 -0
  246. data/test/test-jump.rb +35 -0
  247. data/test/test-list.rb +25 -0
  248. data/test/test-method.rb +34 -0
  249. data/test/test-next.rb +25 -0
  250. data/test/test-output.rb +26 -0
  251. data/test/test-quit.rb +30 -0
  252. data/test/test-raise.rb +25 -0
  253. data/test/test-save.rb +31 -0
  254. data/test/test-scope-var.rb +25 -0
  255. data/test/test-setshow.rb +25 -0
  256. data/test/test-source.rb +25 -0
  257. data/test/test-stepping.rb +26 -0
  258. data/test/test-trace.rb +47 -0
  259. data/test/thread1.rb +26 -0
  260. data/test/trunc-call.rb +31 -0
  261. metadata +364 -0
@@ -0,0 +1,5 @@
1
+ # Module/Package to do the most-common thing: get into the debugger with
2
+ # minimal fuss. Compare with: require "debug"
3
+ require "ruby-debug"
4
+ Debugger.start
5
+ debugger
@@ -0,0 +1,69 @@
1
+ module Debugger
2
+
3
+ module ParseFunctions
4
+ Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))'
5
+
6
+ # Parse 'str' of command 'cmd' as an integer between
7
+ # min and max. If either min or max is nil, that
8
+ # value has no bound.
9
+ def get_int(str, cmd, min=nil, max=nil, default=1)
10
+ return default unless str
11
+ begin
12
+ int = Integer(str)
13
+ if min and int < min
14
+ print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
15
+ return nil
16
+ elsif max and int > max
17
+ print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
18
+ return nil
19
+ end
20
+ return int
21
+ rescue
22
+ print "%s argument '%s' needs to be a number.\n" % [cmd, str]
23
+ return nil
24
+ end
25
+ end
26
+
27
+ # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
28
+ # Any other value raises RuntimeError.
29
+ def get_onoff(arg, default=nil, print_error=true)
30
+ if arg.nil? or arg == ''
31
+ if default.nil?
32
+ if print_error
33
+ print "Expecting 'on', 1, 'off', or 0. Got nothing.\n"
34
+ raise RuntimeError
35
+ end
36
+ return default
37
+ end
38
+ end
39
+ case arg.downcase
40
+ when '1', 'on'
41
+ return true
42
+ when '0', 'off'
43
+ return false
44
+ else
45
+ if print_error
46
+ print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s
47
+ raise RuntimeError
48
+ end
49
+ end
50
+ end
51
+
52
+ # Return 'on' or 'off' for supplied parameter. The parmeter should
53
+ # be true, false or nil.
54
+ def show_onoff(bool)
55
+ if not [TrueClass, FalseClass, NilClass].member?(bool.class)
56
+ return "??"
57
+ end
58
+ return bool ? 'on' : 'off'
59
+ end
60
+
61
+ # Return true if code is syntactically correct for Ruby.
62
+ def syntax_valid?(code)
63
+ eval("BEGIN {return true}\n#{code}", nil, "", 0)
64
+ rescue Exception
65
+ false
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,232 @@
1
+ module Debugger
2
+ class Interface # :nodoc:
3
+ attr_writer :have_readline # true if Readline is available
4
+
5
+ def initialize
6
+ @have_readline = false
7
+ end
8
+
9
+ # Common routine for reporting debugger error messages.
10
+ # Derived classed may want to override this to capture output.
11
+ def errmsg(*args)
12
+ if Debugger.annotate.to_i > 2
13
+ aprint 'error-begin'
14
+ print(*args)
15
+ aprint ''
16
+ else
17
+ print '*** '
18
+ print(*args)
19
+ end
20
+ end
21
+
22
+ # Format msg with gdb-style annotation header
23
+ def afmt(msg, newline="\n")
24
+ "\032\032#{msg}#{newline}"
25
+ end
26
+
27
+ def aprint(msg)
28
+ print afmt(msg)
29
+ end
30
+
31
+ end
32
+
33
+ class LocalInterface < Interface # :nodoc:
34
+ attr_accessor :command_queue
35
+ attr_accessor :histfile
36
+ attr_accessor :history_save
37
+ attr_accessor :history_length
38
+ attr_accessor :restart_file
39
+
40
+ unless defined?(FILE_HISTORY)
41
+ FILE_HISTORY = ".rdebug_hist"
42
+ end
43
+ def initialize()
44
+ super
45
+ @command_queue = []
46
+ @have_readline = false
47
+ @history_save = true
48
+ # take gdb's default
49
+ @history_length = ENV["HISTSIZE"] ? ENV["HISTSIZE"].to_i : 256
50
+ @histfile = File.join(ENV["HOME"]||ENV["HOMEPATH"]||".",
51
+ FILE_HISTORY)
52
+ open(@histfile, 'r') do |file|
53
+ file.each do |line|
54
+ line.chomp!
55
+ Readline::HISTORY << line
56
+ end
57
+ end if File.exist?(@histfile)
58
+ @restart_file = nil
59
+ end
60
+
61
+ def read_command(prompt)
62
+ readline(prompt, true)
63
+ end
64
+
65
+ def confirm(prompt)
66
+ readline(prompt, false)
67
+ end
68
+
69
+ def print(*args)
70
+ STDOUT.printf(*args)
71
+ end
72
+
73
+ def close
74
+ end
75
+
76
+ # Things to do before quitting
77
+ def finalize
78
+ if Debugger.method_defined?("annotate") and Debugger.annotate.to_i > 2
79
+ print "\032\032exited\n\n"
80
+ end
81
+ if Debugger.respond_to?(:save_history)
82
+ Debugger.save_history
83
+ end
84
+ end
85
+
86
+ def readline_support?
87
+ @have_readline
88
+ end
89
+
90
+ private
91
+ begin
92
+ require 'readline'
93
+ class << Debugger
94
+ @have_readline = true
95
+ define_method(:save_history) do
96
+ iface = self.handler.interface
97
+ iface.histfile ||= File.join(ENV["HOME"]||ENV["HOMEPATH"]||".",
98
+ FILE_HISTORY)
99
+ open(iface.histfile, 'w') do |file|
100
+ Readline::HISTORY.to_a.last(iface.history_length).each do |line|
101
+ file.puts line unless line.strip.empty?
102
+ end if defined?(iface.history_save) and iface.history_save
103
+ end rescue nil
104
+ end
105
+ public :save_history
106
+ end
107
+ Debugger.debug_at_exit do
108
+ finalize if respond_to?(:finalize)
109
+ end
110
+
111
+ def readline(prompt, hist)
112
+ Readline::readline(prompt, hist)
113
+ end
114
+ rescue LoadError
115
+ def readline(prompt, hist)
116
+ @histfile = ''
117
+ @hist_save = false
118
+ STDOUT.print prompt
119
+ STDOUT.flush
120
+ line = STDIN.gets
121
+ exit unless line
122
+ line.chomp!
123
+ line
124
+ end
125
+ end
126
+ end
127
+
128
+ class RemoteInterface < Interface # :nodoc:
129
+ attr_accessor :command_queue
130
+ attr_accessor :histfile
131
+ attr_accessor :history_save
132
+ attr_accessor :history_length
133
+ attr_accessor :restart_file
134
+
135
+ def initialize(socket)
136
+ @command_queue = []
137
+ @socket = socket
138
+ @history_save = false
139
+ @history_length = 256
140
+ @histfile = ''
141
+ # Do we read the histfile?
142
+ # open(@histfile, 'r') do |file|
143
+ # file.each do |line|
144
+ # line.chomp!
145
+ # Readline::HISTORY << line
146
+ # end
147
+ # end if File.exist?(@histfile)
148
+ @restart_file = nil
149
+ end
150
+
151
+ def close
152
+ @socket.close
153
+ rescue Exception
154
+ end
155
+
156
+ def confirm(prompt)
157
+ send_command "CONFIRM #{prompt}"
158
+ end
159
+
160
+ def finalize
161
+ end
162
+
163
+ def read_command(prompt)
164
+ send_command "PROMPT #{prompt}"
165
+ end
166
+
167
+ def readline_support?
168
+ false
169
+ end
170
+
171
+ def print(*args)
172
+ @socket.printf(*args)
173
+ end
174
+
175
+ private
176
+
177
+ def send_command(msg)
178
+ @socket.puts msg
179
+ result = @socket.gets
180
+ raise IOError unless result
181
+ result.chomp
182
+ end
183
+ end
184
+
185
+ class ScriptInterface < Interface # :nodoc:
186
+ attr_accessor :command_queue
187
+ attr_accessor :histfile
188
+ attr_accessor :history_save
189
+ attr_accessor :history_length
190
+ attr_accessor :restart_file
191
+ def initialize(file, out, verbose=false)
192
+ super()
193
+ @command_queue = []
194
+ @file = file.respond_to?(:gets) ? file : open(file)
195
+ @out = out
196
+ @verbose = verbose
197
+ @history_save = false
198
+ @history_length = 256 # take gdb default
199
+ @histfile = ''
200
+ end
201
+
202
+ def finalize
203
+ end
204
+
205
+ def read_command(prompt)
206
+ while result = @file.gets
207
+ puts "# #{result}" if @verbose
208
+ next if result =~ /^\s*#/
209
+ next if result.strip.empty?
210
+ break
211
+ end
212
+ raise IOError unless result
213
+ result.chomp!
214
+ end
215
+
216
+ def readline_support?
217
+ false
218
+ end
219
+
220
+ def confirm(prompt)
221
+ 'y'
222
+ end
223
+
224
+ def print(*args)
225
+ @out.printf(*args)
226
+ end
227
+
228
+ def close
229
+ @file.close
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,474 @@
1
+ require_relative 'interface'
2
+ require_relative 'command'
3
+
4
+ module Debugger
5
+
6
+ # Should this be a mixin?
7
+ class Processor # :nodoc
8
+ attr_accessor :interface
9
+
10
+ # Format msg with gdb-style annotation header
11
+ def afmt(msg, newline="\n")
12
+ "\032\032#{msg}#{newline}"
13
+ end
14
+
15
+ def aprint(msg)
16
+ print afmt(msg) if Debugger.annotate.to_i > 2
17
+ end
18
+
19
+ # FIXME: use delegate?
20
+ def errmsg(*args)
21
+ @interface.errmsg(*args)
22
+ end
23
+
24
+ # Callers of this routine should make sure to use comma to
25
+ # separate format argments rather than %. Otherwise it seems that
26
+ # if the string you want to print has format specifier, which
27
+ # could happen if you are trying to show say a source-code line
28
+ # with "puts" or "print" in it, this print routine will give an
29
+ # error saying it is looking for more arguments.
30
+ def print(*args)
31
+ @interface.print(*args)
32
+ end
33
+
34
+ end
35
+
36
+ class CommandProcessor < Processor # :nodoc:
37
+ attr_reader :display
38
+
39
+ # FIXME: get from Command regexp method.
40
+ @@Show_breakpoints_postcmd = [
41
+ /^\s*b(?:reak)?/,
42
+ /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix,
43
+ /^\s*del(?:ete)?(?:\s+(.*))?$/ix,
44
+ /^\s* dis(?:able)? (?:\s+(.*))?$/ix,
45
+ /^\s* en(?:able)? (?:\s+(.*))?$/ix,
46
+ # "tbreak", "clear",
47
+ ]
48
+ @@Show_annotations_run = [
49
+ /^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/,
50
+ /^\s*fin(?:ish)?$/,
51
+ /^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/,
52
+ /^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/
53
+ ]
54
+
55
+ @@Show_annotations_postcmd = [
56
+ /^\s* down (?:\s+(.*))? .*$/x,
57
+ /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x,
58
+ /^\s* u(?:p)? (?:\s+(.*))?$/x
59
+ ]
60
+
61
+ def initialize(interface = LocalInterface.new)
62
+ @interface = interface
63
+ @display = []
64
+
65
+ @mutex = Mutex.new
66
+ @last_cmd = nil
67
+ @last_file = nil # Filename the last time we stopped
68
+ @last_line = nil # line number the last time we stopped
69
+ @debugger_breakpoints_were_empty = false # Show breakpoints 1st time
70
+ @debugger_displays_were_empty = true # No display 1st time
71
+ @debugger_context_was_dead = true # Assume we haven't started.
72
+ end
73
+
74
+ def interface=(interface)
75
+ @mutex.synchronize do
76
+ @interface.close if @interface
77
+ @interface = interface
78
+ end
79
+ end
80
+
81
+ require 'pathname' # For cleanpath
82
+
83
+ # Regularize file name.
84
+ # This is also used as a common funnel place if basename is
85
+ # desired or if we are working remotely and want to change the
86
+ # basename. Or we are eliding filenames.
87
+ def self.canonic_file(filename)
88
+ # For now we want resolved filenames
89
+ if Command.settings[:basename]
90
+ File.basename(filename)
91
+ else
92
+ # Cache this?
93
+ Pathname.new(filename).cleanpath.to_s
94
+ end
95
+ end
96
+
97
+ def self.print_location_and_text(file, line)
98
+ file_line = "%s:%s\n%s" % [canonic_file(file), line,
99
+ Debugger.line_at(file, line)]
100
+ # FIXME: use annotations routines
101
+ if Debugger.annotate.to_i > 2
102
+ file_line = "\032\032source #{file_line}"
103
+ elsif ENV['EMACS']
104
+ file_line = "\032\032#{file_line}"
105
+ end
106
+ print file_line
107
+ end
108
+
109
+ def self.protect(mname)
110
+ alias_method "__#{mname}", mname
111
+ module_eval %{
112
+ def #{mname}(*args)
113
+ @mutex.synchronize do
114
+ return unless @interface
115
+ __#{mname}(*args)
116
+ end
117
+ rescue IOError, Errno::EPIPE
118
+ self.interface = nil
119
+ rescue SignalException
120
+ raise
121
+ rescue Exception
122
+ print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
123
+ print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
124
+ end
125
+ }
126
+ end
127
+
128
+ def at_breakpoint(context, breakpoint)
129
+ aprint 'stopped' if Debugger.annotate.to_i > 2
130
+ n = Debugger.breakpoints.index(breakpoint) + 1
131
+ file = CommandProcessor.canonic_file(breakpoint.source)
132
+ line = breakpoint.pos
133
+ if Debugger.annotate.to_i > 2
134
+ print afmt("source #{file}:#{line}")
135
+ end
136
+ print "Breakpoint %d at %s:%s\n", n, file, line
137
+ end
138
+ protect :at_breakpoint
139
+
140
+ def at_catchpoint(context, excpt)
141
+ aprint 'stopped' if Debugger.annotate.to_i > 2
142
+ file = CommandProcessor.canonic_file(context.frame_file(0))
143
+ line = context.frame_line(0)
144
+ print afmt("%s:%d" % [file, line]) if ENV['EMACS']
145
+ print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class
146
+ fs = context.stack_size
147
+ tb = caller(0)[-fs..-1]
148
+ if tb
149
+ for i in tb
150
+ print "\tfrom %s\n", i
151
+ end
152
+ end
153
+ end
154
+ protect :at_catchpoint
155
+
156
+ def at_tracing(context, file, line)
157
+ return if defined?(Debugger::RDEBUG_FILE) &&
158
+ Debugger::RDEBUG_FILE == file # Don't trace ourself
159
+ @last_file = CommandProcessor.canonic_file(file)
160
+ file = CommandProcessor.canonic_file(file)
161
+ unless file == @last_file and @last_line == line and
162
+ Command.settings[:tracing_plus]
163
+ print "Tracing(%d):%s:%s %s",
164
+ context.thnum, file, line, Debugger.line_at(file, line)
165
+ @last_file = file
166
+ @last_line = line
167
+ end
168
+ always_run(context, file, line, 2)
169
+ end
170
+ protect :at_tracing
171
+
172
+ def at_line(context, file, line)
173
+ process_commands(context, file, line)
174
+ end
175
+ protect :at_line
176
+
177
+ def at_return(context, file, line)
178
+ context.stop_frame = -1
179
+ process_commands(context, file, line)
180
+ end
181
+
182
+ private
183
+
184
+ # The prompt shown before reading a command.
185
+ def prompt(context)
186
+ p = '(rdb:%s) ' % (context.dead? ? 'post-mortem' : context.thnum)
187
+ p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
188
+ Debugger.annotate.to_i > 2
189
+ return p
190
+ end
191
+
192
+ # Run these commands, for example display commands or possibly
193
+ # the list or irb in an "autolist" or "autoirb".
194
+ # We return a list of commands that are acceptable to run bound
195
+ # to the current state.
196
+ def always_run(context, file, line, run_level)
197
+ event_cmds = Command.commands.select{|cmd| cmd.event }
198
+
199
+ # Remove some commands in post-mortem
200
+ event_cmds = event_cmds.find_all do |cmd|
201
+ cmd.allow_in_post_mortem
202
+ end if context.dead?
203
+
204
+ state = State.new do |s|
205
+ s.context = context
206
+ s.file = file
207
+ s.line = line
208
+ s.binding = context.frame_binding(0)
209
+ s.display = display
210
+ s.interface = interface
211
+ s.commands = event_cmds
212
+ end
213
+ @interface.state = state if @interface.respond_to?('state=')
214
+
215
+ # Bind commands to the current state.
216
+ commands = event_cmds.map{|cmd| cmd.new(state)}
217
+
218
+ commands.select do |cmd|
219
+ cmd.class.always_run >= run_level
220
+ end.each {|cmd| cmd.execute}
221
+ return state, commands
222
+ end
223
+
224
+ # Handle debugger commands
225
+ def process_commands(context, file, line)
226
+ state, commands = always_run(context, file, line, 1)
227
+ $rdebug_state = state if Command.settings[:debuggertesting]
228
+ splitter = lambda do |str|
229
+ str.split(/;/).inject([]) do |m, v|
230
+ if m.empty?
231
+ m << v
232
+ else
233
+ if m.last[-1] == ?\\
234
+ m.last[-1,1] = ''
235
+ m.last << ';' << v
236
+ else
237
+ m << v
238
+ end
239
+ end
240
+ m
241
+ end
242
+ end
243
+
244
+ preloop(commands, context)
245
+ CommandProcessor.print_location_and_text(file, line)
246
+ while !state.proceed?
247
+ input = if @interface.command_queue.empty?
248
+ @interface.read_command(prompt(context))
249
+ else
250
+ @interface.command_queue.shift
251
+ end
252
+ break unless input
253
+ catch(:debug_error) do
254
+ if input == ""
255
+ next unless @last_cmd
256
+ input = @last_cmd
257
+ else
258
+ @last_cmd = input
259
+ end
260
+ splitter[input].each do |cmd|
261
+ one_cmd(commands, context, cmd)
262
+ postcmd(commands, context, cmd)
263
+ end
264
+ end
265
+ end
266
+ postloop(commands, context)
267
+ end # process_commands
268
+
269
+ def one_cmd(commands, context, input)
270
+ if cmd = commands.find{ |c| c.match(input) }
271
+ if context.dead? && cmd.class.need_context
272
+ p cmd
273
+ print "Command is unavailable\n"
274
+ else
275
+ cmd.execute
276
+ end
277
+ else
278
+ unknown_cmd = commands.find{ |c| c.class.unknown }
279
+ if unknown_cmd
280
+ unknown_cmd.execute
281
+ else
282
+ errmsg "Unknown command: \"#{input}\". Try \"help\".\n"
283
+ end
284
+ end
285
+ end
286
+
287
+ def preloop(commands, context)
288
+ aprint('stopped') if Debugger.annotate.to_i > 2
289
+ if context.dead?
290
+ unless @debugger_context_was_dead
291
+ if Debugger.annotate.to_i > 2
292
+ aprint('exited')
293
+ print "The program finished.\n"
294
+ end
295
+ @debugger_context_was_dead = true
296
+ end
297
+ end
298
+
299
+ if Debugger.annotate.to_i > 2
300
+ # if we are here, the stack frames have changed outside the
301
+ # command loop (e.g. after a "continue" command), so we show
302
+ # the annotations again
303
+ breakpoint_annotations(commands, context)
304
+ display_annotations(commands, context)
305
+ annotation('stack', commands, context, "where")
306
+ annotation('variables', commands, context, "info variables") unless
307
+ context.dead?
308
+ end
309
+ end
310
+
311
+ def postcmd(commands, context, cmd)
312
+ if Debugger.annotate.to_i > 0
313
+ cmd = @last_cmd unless cmd
314
+ breakpoint_annotations(commands, context) if
315
+ @@Show_breakpoints_postcmd.find{|pat| cmd =~ pat}
316
+ display_annotations(commands, context)
317
+ if @@Show_annotations_postcmd.find{|pat| cmd =~ pat}
318
+ annotation('stack', commands, context, "where") if
319
+ context.stack_size > 0
320
+ annotation('variables', commands, context, "info variables") unless
321
+ context.dead?
322
+ end
323
+ if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat}
324
+ aprint 'starting' if Debugger.annotate.to_i > 2
325
+
326
+ @debugger_context_was_dead = false
327
+ end
328
+ end
329
+ end
330
+
331
+ def postloop(commands, context)
332
+ end
333
+
334
+ def annotation(label, commands, context, cmd)
335
+ print afmt(label)
336
+ one_cmd(commands, context, cmd)
337
+ ### FIXME ANNOTATE: the following line should be deleted
338
+ print "\032\032\n"
339
+ end
340
+
341
+ def breakpoint_annotations(commands, context)
342
+ unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty
343
+ annotation('breakpoints', commands, context, "info breakpoints")
344
+ @debugger_breakpoints_were_empty = Debugger.breakpoints.empty?
345
+ end
346
+ end
347
+
348
+ def display_annotations(commands, context)
349
+ return if display.empty?
350
+ # have_display = display.find{|d| d[0]}
351
+ # return unless have_display and @debugger_displays_were_empty
352
+ # @debugger_displays_were_empty = have_display
353
+ annotation('display', commands, context, "display")
354
+ end
355
+
356
+ class State # :nodoc:
357
+ attr_accessor :context, :file, :line, :binding
358
+ attr_accessor :frame_pos, :previous_line, :display
359
+ attr_accessor :interface, :commands
360
+
361
+ def initialize
362
+ super()
363
+ @frame_pos = 0
364
+ @previous_line = nil
365
+ @proceed = false
366
+ yield self
367
+ end
368
+
369
+ # FIXME: use delegate?
370
+ def errmsg(*args)
371
+ @interface.errmsg(*args)
372
+ end
373
+
374
+ def print(*args)
375
+ @interface.print(*args)
376
+ end
377
+
378
+ def confirm(*args)
379
+ @interface.confirm(*args)
380
+ end
381
+
382
+ def proceed?
383
+ @proceed
384
+ end
385
+
386
+ def proceed
387
+ @proceed = true
388
+ end
389
+ end
390
+ end
391
+
392
+ class ControlCommandProcessor < Processor # :nodoc:
393
+ def initialize(interface)
394
+ super()
395
+ @interface = interface
396
+ @debugger_context_was_dead = true # Assume we haven't started.
397
+ end
398
+
399
+ def process_commands(verbose=false)
400
+ control_cmds = Command.commands.select do |cmd|
401
+ cmd.allow_in_control
402
+ end
403
+ state = State.new(@interface, control_cmds)
404
+ commands = control_cmds.map{|cmd| cmd.new(state) }
405
+
406
+ unless @debugger_context_was_dead
407
+ if Debugger.annotate.to_i > 2
408
+ aprint 'exited'
409
+ print "The program finished.\n"
410
+ end
411
+ @debugger_context_was_dead = true
412
+ end
413
+
414
+ while input = @interface.read_command(prompt(nil))
415
+ print "+#{input}" if verbose
416
+ catch(:debug_error) do
417
+ if cmd = commands.find{|c| c.match(input) }
418
+ cmd.execute
419
+ else
420
+ errmsg "Unknown command\n"
421
+ end
422
+ end
423
+ end
424
+ rescue IOError, Errno::EPIPE
425
+ rescue Exception
426
+ print "INTERNAL ERROR!!! #{$!}\n" rescue nil
427
+ print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
428
+ ensure
429
+ @interface.close
430
+ end
431
+
432
+ # The prompt shown before reading a command.
433
+ # Note: have an unused 'context' parameter to match the local interface.
434
+ def prompt(context)
435
+ p = '(rdb:ctrl) '
436
+ p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if
437
+ Debugger.annotate.to_i > 2
438
+ return p
439
+ end
440
+
441
+ class State # :nodoc:
442
+ attr_reader :commands, :interface
443
+
444
+ def initialize(interface, commands)
445
+ @interface = interface
446
+ @commands = commands
447
+ end
448
+
449
+ def proceed
450
+ end
451
+
452
+ def errmsg(*args)
453
+ @interface.print(*args)
454
+ end
455
+
456
+ def print(*args)
457
+ @interface.print(*args)
458
+ end
459
+
460
+ def confirm(*args)
461
+ 'y'
462
+ end
463
+
464
+ def context
465
+ nil
466
+ end
467
+
468
+ def file
469
+ errmsg "No filename given.\n"
470
+ throw :debug_error
471
+ end
472
+ end # State
473
+ end
474
+ end