ruby-debug 0.7.5 → 0.8
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.
- data/CHANGES +5 -0
- data/bin/rdebug +9 -12
- data/cli/ruby-debug.rb +117 -0
- data/{lib → cli}/ruby-debug/command.rb +2 -13
- data/{lib → cli}/ruby-debug/commands/breakpoints.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/catchpoint.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/control.rb +2 -0
- data/{lib → cli}/ruby-debug/commands/display.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/eval.rb +1 -0
- data/{lib → cli}/ruby-debug/commands/frame.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/help.rb +1 -1
- data/{lib → cli}/ruby-debug/commands/irb.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/list.rb +2 -2
- data/{lib → cli}/ruby-debug/commands/method.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/script.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/settings.rb +4 -0
- data/{lib → cli}/ruby-debug/commands/stepping.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/threads.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/tmate.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/trace.rb +0 -0
- data/{lib → cli}/ruby-debug/commands/variables.rb +0 -0
- data/{lib → cli}/ruby-debug/interface.rb +0 -0
- data/{lib → cli}/ruby-debug/processor.rb +4 -2
- metadata +43 -39
- data/Rakefile +0 -120
- data/ext/extconf.rb +0 -18
- data/ext/ruby_debug.c +0 -2167
- data/lib/ruby-debug.rb +0 -330
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
|