ruby-debug 0.7.5 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ruby-debug.rb DELETED
@@ -1,330 +0,0 @@
1
- require 'pp'
2
- require 'stringio'
3
- require "socket"
4
- require 'thread'
5
- require 'ruby_debug.so'
6
- require 'ruby-debug/processor'
7
-
8
- SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
9
- SCRIPT_TIMESTAMPS__ = {} unless defined? SCRIPT_TIMESTAMPS__
10
-
11
- module Debugger
12
- PORT = 8989
13
-
14
- @processor = CommandProcessor.new
15
- @reload_source_on_change = false
16
-
17
- class Context
18
- def interrupt
19
- self.stop_next = 1
20
- end
21
-
22
- private
23
-
24
- def processor
25
- Debugger.processor
26
- end
27
-
28
- def at_breakpoint(breakpoint)
29
- processor.at_breakpoint(self, breakpoint)
30
- end
31
-
32
- def at_catchpoint(excpt)
33
- processor.at_catchpoint(self, excpt)
34
- end
35
-
36
- def at_tracing(file, line)
37
- processor.at_tracing(self, file, line)
38
- end
39
-
40
- def at_line(file, line)
41
- processor.at_line(self, file, line)
42
- end
43
- end
44
-
45
- class << self
46
- attr_accessor :processor
47
-
48
- # stop main thread when remote connection established
49
- attr_accessor :stop_on_connect
50
-
51
- # in remote mode, wait for the remote connection
52
- attr_accessor :wait_connection
53
-
54
- # if <tt>true</tt>, checks the modification time of source files and reloads if it was modified
55
- attr_accessor :reload_source_on_change
56
-
57
- attr_reader :thread, :control_thread
58
-
59
- #
60
- # Interrupts the current thread
61
- #
62
- def interrupt
63
- current_context.interrupt
64
- end
65
-
66
- #
67
- # Interrupts the last debugged thread
68
- #
69
- def interrupt_last
70
- if context = last_context
71
- return nil unless context.thread.alive?
72
- context.interrupt
73
- end
74
- context
75
- end
76
-
77
- def interface=(value) # :nodoc:
78
- processor.interface = value
79
- end
80
-
81
- #
82
- # Starts a remote debugger.
83
- #
84
- def start_remote(host = nil, port = PORT, post_mortem = false)
85
- return if @thread
86
- return if started?
87
-
88
- self.interface = nil
89
- start
90
- self.post_mortem if post_mortem
91
-
92
- if port.kind_of?(Array)
93
- cmd_port, ctrl_port = port
94
- else
95
- cmd_port, ctrl_port = port, port + 1
96
- end
97
-
98
- start_control(host, ctrl_port)
99
-
100
- mutex = Mutex.new
101
- proceed = ConditionVariable.new
102
-
103
- @thread = DebugThread.new do
104
- server = TCPServer.new(host, cmd_port)
105
- while (session = server.accept)
106
- self.interface = RemoteInterface.new(session)
107
- if wait_connection
108
- mutex.synchronize do
109
- proceed.signal
110
- end
111
- else
112
- stop_main_thread
113
- end
114
- end
115
- end
116
- if wait_connection
117
- mutex.synchronize do
118
- proceed.wait(mutex)
119
- end
120
- stop_main_thread
121
- end
122
- end
123
- alias start_server start_remote
124
-
125
- def start_control(host = nil, ctrl_port = PORT + 1)
126
- raise "Debugger is not started" unless started?
127
- return if @control_thread
128
- @control_thread = DebugThread.new do
129
- server = TCPServer.new(host, ctrl_port)
130
- while (session = server.accept)
131
- interface = RemoteInterface.new(session)
132
- processor = ControlCommandProcessor.new(interface)
133
- processor.process_commands
134
- end
135
- end
136
- end
137
-
138
- #
139
- # Connects to the remote debugger
140
- #
141
- def start_client(host = 'localhost', port = PORT)
142
- require "socket"
143
- interface = Debugger::LocalInterface.new
144
- socket = TCPSocket.new(host, port)
145
- puts "Connected."
146
-
147
- catch(:exit) do
148
- while (line = socket.gets)
149
- case line
150
- when /^PROMPT (.*)$/
151
- input = interface.read_command($1)
152
- throw :exit unless input
153
- socket.puts input
154
- when /^CONFIRM (.*)$/
155
- input = interface.confirm($1)
156
- throw :exit unless input
157
- socket.puts input
158
- else
159
- print line
160
- end
161
- end
162
- end
163
- socket.close
164
- end
165
-
166
- def stop_main_thread # :nodoc:
167
- return unless stop_on_connect
168
-
169
- context = thread_context(Thread.main)
170
- context.stop_next = 2
171
- end
172
- private :stop_main_thread
173
-
174
- def source_for(file) # :nodoc:
175
- finder = lambda do
176
- if File.exists?(file)
177
- if SCRIPT_LINES__[file].nil? || SCRIPT_LINES__[file] == true
178
- SCRIPT_LINES__[file] = File.readlines(file)
179
- end
180
-
181
- change_time = test(?M, file)
182
- SCRIPT_TIMESTAMPS__[file] ||= change_time
183
- if @reload_source_on_change && SCRIPT_TIMESTAMPS__[file] < change_time
184
- SCRIPT_LINES__[file] = File.readlines(file)
185
- end
186
-
187
- SCRIPT_LINES__[file]
188
- end
189
- end
190
-
191
- Dir.chdir(File.dirname($0)){finder.call} || finder.call ||
192
- (SCRIPT_LINES__[file] == true ? nil : SCRIPT_LINES__[file])
193
- end
194
-
195
- def source_reload
196
- SCRIPT_LINES__.keys.each do |file|
197
- next unless File.exists?(file)
198
- SCRIPT_LINES__[file] = nil
199
- end
200
- end
201
-
202
- def line_at(file, line) # :nodoc:
203
- lines = source_for(file)
204
- if lines
205
- line = lines[line-1]
206
- return "\n" unless line
207
- return "#{line.gsub(/^\s+/, '').chomp}\n"
208
- end
209
- return "\n"
210
- end
211
-
212
- #
213
- # Runs a script file
214
- #
215
- def run_script(file, out = processor.interface)
216
- interface = ScriptInterface.new(file, out)
217
- processor = ControlCommandProcessor.new(interface)
218
- processor.process_commands
219
- end
220
-
221
- #
222
- # Activates the post-mortem mode. There are two ways of using it:
223
- #
224
- # == Global post-mortem mode
225
- # By calling Debugger.post_mortem method without a block, you install
226
- # at_exit hook that intercepts any unhandled by your script exceptions
227
- # and enables post-mortem mode.
228
- #
229
- # == Local post-mortem mode
230
- #
231
- # If you know that a particular block of code raises an exception you can
232
- # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g.
233
- #
234
- # def offender
235
- # raise 'error'
236
- # end
237
- # Debugger.post_mortem do
238
- # ...
239
- # offender
240
- # ...
241
- # end
242
- def post_mortem
243
- raise "Post-mortem is already activated" if self.post_mortem?
244
- self.post_mortem = true
245
- if block_given?
246
- begin
247
- yield
248
- rescue Exception => exp
249
- handle_post_mortem(exp)
250
- raise
251
- ensure
252
- self.post_mortem = false
253
- end
254
- else
255
- debug_at_exit do
256
- handle_post_mortem($!) if $! && post_mortem?
257
- end
258
- end
259
- end
260
-
261
- def handle_post_mortem(exp)
262
- return if exp.__debug_context.stack_size == 0
263
- Debugger.suspend
264
- orig_tracing = Debugger.tracing, Debugger.current_context.tracing
265
- Debugger.tracing = Debugger.current_context.tracing = false
266
- processor.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
267
- ensure
268
- Debugger.tracing, Debugger.current_context.tracing = orig_tracing
269
- Debugger.resume
270
- end
271
- private :handle_post_mortem
272
- end
273
- end
274
-
275
- class Exception # :nodoc:
276
- attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
277
- end
278
-
279
- module Kernel
280
- #
281
- # Stops the current thread after a number of _steps_ made.
282
- #
283
- def debugger(steps = 1)
284
- Debugger.current_context.stop_next = steps
285
- end
286
-
287
- #
288
- # Returns a binding of n-th call frame
289
- #
290
- def binding_n(n = 0)
291
- Debugger.current_context.frame_binding[n+1]
292
- end
293
- end
294
-
295
- class Module
296
- #
297
- # Wraps the +meth+ method with Debugger.start {...} block.
298
- #
299
- def debug_method(meth)
300
- old_meth = "__debugee_#{meth}"
301
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
302
- alias_method old_meth.to_sym, meth
303
- class_eval <<-EOD
304
- def #{meth}(*args, &block)
305
- Debugger.start do
306
- debugger 2
307
- #{old_meth}(*args, &block)
308
- end
309
- end
310
- EOD
311
- end
312
-
313
- #
314
- # Wraps the +meth+ method with Debugger.post_mortem {...} block.
315
- #
316
- def post_mortem_method(meth)
317
- old_meth = "__postmortem_#{meth}"
318
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
319
- alias_method old_meth.to_sym, meth
320
- class_eval <<-EOD
321
- def #{meth}(*args, &block)
322
- Debugger.start do |dbg|
323
- dbg.post_mortem do
324
- #{old_meth}(*args, &block)
325
- end
326
- end
327
- end
328
- EOD
329
- end
330
- end