ruby-debug19 0.11.5
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/AUTHORS +9 -0
- data/LICENSE +23 -0
- data/bin/rdebug +415 -0
- data/cli/ruby-debug.rb +176 -0
- data/cli/ruby-debug/command.rb +228 -0
- data/cli/ruby-debug/commands/breakpoints.rb +153 -0
- data/cli/ruby-debug/commands/catchpoint.rb +55 -0
- data/cli/ruby-debug/commands/condition.rb +49 -0
- data/cli/ruby-debug/commands/continue.rb +38 -0
- data/cli/ruby-debug/commands/control.rb +107 -0
- data/cli/ruby-debug/commands/display.rb +120 -0
- data/cli/ruby-debug/commands/edit.rb +48 -0
- data/cli/ruby-debug/commands/enable.rb +202 -0
- data/cli/ruby-debug/commands/eval.rb +176 -0
- data/cli/ruby-debug/commands/finish.rb +42 -0
- data/cli/ruby-debug/commands/frame.rb +301 -0
- data/cli/ruby-debug/commands/help.rb +56 -0
- data/cli/ruby-debug/commands/info.rb +469 -0
- data/cli/ruby-debug/commands/irb.rb +123 -0
- data/cli/ruby-debug/commands/kill.rb +51 -0
- data/cli/ruby-debug/commands/list.rb +94 -0
- data/cli/ruby-debug/commands/method.rb +84 -0
- data/cli/ruby-debug/commands/quit.rb +39 -0
- data/cli/ruby-debug/commands/reload.rb +40 -0
- data/cli/ruby-debug/commands/save.rb +90 -0
- data/cli/ruby-debug/commands/set.rb +237 -0
- data/cli/ruby-debug/commands/show.rb +253 -0
- data/cli/ruby-debug/commands/source.rb +36 -0
- data/cli/ruby-debug/commands/stepping.rb +81 -0
- data/cli/ruby-debug/commands/threads.rb +189 -0
- data/cli/ruby-debug/commands/tmate.rb +36 -0
- data/cli/ruby-debug/commands/trace.rb +57 -0
- data/cli/ruby-debug/commands/variables.rb +199 -0
- data/cli/ruby-debug/debugger.rb +5 -0
- data/cli/ruby-debug/helper.rb +69 -0
- data/cli/ruby-debug/interface.rb +232 -0
- data/cli/ruby-debug/processor.rb +474 -0
- data/rdbg.rb +33 -0
- metadata +122 -0
data/AUTHORS
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (C) 2005 Kent Sibilev <ksibilev@yahoo.com>
|
2
|
+
All rights reserved.
|
3
|
+
*
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions
|
6
|
+
are met:
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
*
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
15
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
16
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
17
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
18
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
19
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
20
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
21
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
22
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
23
|
+
SUCH DAMAGE.
|
data/bin/rdebug
ADDED
@@ -0,0 +1,415 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#=== Summary
|
4
|
+
#
|
5
|
+
#A command-line front-end to the Ruby debugger, <tt>ruby-debug</tt>, the
|
6
|
+
#Fast Ruby Debugger.
|
7
|
+
#
|
8
|
+
#Command invocation:
|
9
|
+
#
|
10
|
+
# rdebug [options] [--] [script-options] ruby-script-to-debug
|
11
|
+
# rdebug [options] [script-options] [--client]
|
12
|
+
# rdebug [--version | --help]
|
13
|
+
#
|
14
|
+
#=== Options
|
15
|
+
#
|
16
|
+
#<tt>-A | --annotate</tt> <i>level</i>::
|
17
|
+
# Set gdb-style annotation to <i>level</i>, a number. Additional
|
18
|
+
# information is output automatically when program state is
|
19
|
+
# changed. This can be used by front-ends such as GNU Emacs to post
|
20
|
+
# this updated information without having to poll for it.
|
21
|
+
#
|
22
|
+
#<tt>--client</tt>::
|
23
|
+
# Connect to a remote debugger. Used with another rdebug invocation
|
24
|
+
# using <tt>--server</tt>. See also <tt>--host</tt> and
|
25
|
+
# <tt>--cport</tt> options
|
26
|
+
#
|
27
|
+
#<tt>--cport=</tt><i>port</i>::
|
28
|
+
# Use port <i>port</i> for access to debugger control.
|
29
|
+
#
|
30
|
+
#<tt>-d | --debug</tt>::
|
31
|
+
# Set $DEBUG true.
|
32
|
+
#
|
33
|
+
#<tt>--emacs</tt>::
|
34
|
+
# Activates full GNU Emacs mode. Is the equivalent of setting the
|
35
|
+
# options <tt>--emacs-basic --annotate=3 --no-stop --no-control
|
36
|
+
# --post-mortem</tt>.
|
37
|
+
#
|
38
|
+
#<tt>--emacs-basic</tt>::
|
39
|
+
# Activates GNU Emacs mode. Debugger prompts are prefaced with two
|
40
|
+
# octal 032 characters.
|
41
|
+
#
|
42
|
+
#<tt>-h | --host=</tt><i>host</i>::
|
43
|
+
# Use host name <i>host</i> for remote debugging.
|
44
|
+
#
|
45
|
+
#<tt>-I | --include</tt> <i>path</i>
|
46
|
+
# Add <i>path</i> to <tt>$LOAD_PATH</tt>
|
47
|
+
#
|
48
|
+
#<tt>-m | --post-mortem</tt>::
|
49
|
+
# Activate post-mortem mode.
|
50
|
+
#
|
51
|
+
#<tt>--no-control</tt>::
|
52
|
+
# Do not automatically start control thread.
|
53
|
+
#
|
54
|
+
#<tt>--no-stop</tt>::
|
55
|
+
# Do not stop when script is loaded.
|
56
|
+
#
|
57
|
+
#<tt>-p | --port=PORT</tt>::
|
58
|
+
# Host name used for remote debugging.
|
59
|
+
#
|
60
|
+
#<tt>-r | --require</tt><i>script</i>::
|
61
|
+
# Require the library, before executing your script.
|
62
|
+
#
|
63
|
+
#<tt>--script</tt> <i>file</i>::
|
64
|
+
# Run debugger script file <i>file</i>
|
65
|
+
#
|
66
|
+
#<tt>-x | --trace</tt>::
|
67
|
+
# Show lines before executing them.
|
68
|
+
#
|
69
|
+
#<tt>--no-quit</tt>::
|
70
|
+
# Do not quit when script terminates. Instead rerun the
|
71
|
+
# program.
|
72
|
+
#
|
73
|
+
#<tt>--version</tt>::
|
74
|
+
# Show the version number and exit.
|
75
|
+
#
|
76
|
+
#<tt>--verbose</tt>::
|
77
|
+
# Turn on verbose mode.
|
78
|
+
#
|
79
|
+
#<tt>--v</tt>::
|
80
|
+
# Print the version number, then turn on verbose mode if
|
81
|
+
# a script name is given. If no script name is given
|
82
|
+
# just exit after printing the version number.
|
83
|
+
#
|
84
|
+
#<tt>--nx</tt>::
|
85
|
+
# Don’t execute commands found in any initialization
|
86
|
+
# files, e.g. <tt>.rdebugrc</tt>.
|
87
|
+
#
|
88
|
+
#<tt>--keep-frame-binding</tt>::
|
89
|
+
# Keep frame bindings.
|
90
|
+
#
|
91
|
+
#<tt>--script=</tt><i>file</i>::
|
92
|
+
# Name of the script file to run
|
93
|
+
#
|
94
|
+
#<tt>-s | --server</tt>::
|
95
|
+
# Listen for remote connections. Another rdebug session
|
96
|
+
# accesses using the <tt>--client</tt> option. See also the
|
97
|
+
# <tt>--host</tt>, <tt>--port</tt> and <tt>--cport</tt> options
|
98
|
+
#
|
99
|
+
#<tt>-w | --wait</tt>::
|
100
|
+
# Wait for a client connection; implies <tt>-s</tt> option.
|
101
|
+
#
|
102
|
+
#<tt>--help</tt>::
|
103
|
+
# Show invocation help and exit.
|
104
|
+
|
105
|
+
require 'rubygems'
|
106
|
+
require 'optparse'
|
107
|
+
require 'ostruct'
|
108
|
+
require_relative '../cli/ruby-debug'
|
109
|
+
|
110
|
+
def debug_program(options)
|
111
|
+
# Make sure Ruby script syntax checks okay.
|
112
|
+
# Otherwise we get a load message that looks like rdebug has
|
113
|
+
# a problem.
|
114
|
+
output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1`
|
115
|
+
if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/
|
116
|
+
puts output
|
117
|
+
exit $?.exitstatus
|
118
|
+
end
|
119
|
+
print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2
|
120
|
+
|
121
|
+
# Record where we are we can know if the call stack has been
|
122
|
+
# truncated or not.
|
123
|
+
Debugger.start_sentinal=caller(0)[1]
|
124
|
+
|
125
|
+
bt = Debugger.debug_load(Debugger::PROG_SCRIPT, options.stop, false)
|
126
|
+
if bt
|
127
|
+
if options.post_mortem
|
128
|
+
Debugger.handle_post_mortem(bt)
|
129
|
+
else
|
130
|
+
print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
|
131
|
+
print "Uncaught exception: #{bt}\n"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Do a shell-like path lookup for prog_script and return the results.
|
137
|
+
# If we can't find anything return prog_script.
|
138
|
+
def whence_file(prog_script)
|
139
|
+
if prog_script.index(File::SEPARATOR)
|
140
|
+
# Don't search since this name has path separator components
|
141
|
+
return prog_script
|
142
|
+
end
|
143
|
+
for dirname in ENV['PATH'].split(File::PATH_SEPARATOR) do
|
144
|
+
prog_script_try = File.join(dirname, prog_script)
|
145
|
+
return prog_script_try if File.exist?(prog_script_try)
|
146
|
+
end
|
147
|
+
# Failure
|
148
|
+
return prog_script
|
149
|
+
end
|
150
|
+
|
151
|
+
options = OpenStruct.new(
|
152
|
+
'annotate' => Debugger.annotate,
|
153
|
+
'client' => false,
|
154
|
+
'control' => true,
|
155
|
+
'cport' => Debugger::PORT + 1,
|
156
|
+
'frame_bind' => false,
|
157
|
+
'host' => nil,
|
158
|
+
'quit' => true,
|
159
|
+
'no_rewrite_program' => false,
|
160
|
+
'stop' => true,
|
161
|
+
'nx' => false,
|
162
|
+
'port' => Debugger::PORT,
|
163
|
+
'post_mortem' => false,
|
164
|
+
'restart_script' => nil,
|
165
|
+
'script' => nil,
|
166
|
+
'server' => false,
|
167
|
+
'tracing' => false,
|
168
|
+
'verbose_long' => false,
|
169
|
+
'wait' => false
|
170
|
+
)
|
171
|
+
|
172
|
+
def process_options(options)
|
173
|
+
program = File.basename($0)
|
174
|
+
opts = OptionParser.new do |opts|
|
175
|
+
opts.banner = <<EOB
|
176
|
+
#{program} #{Debugger::VERSION}
|
177
|
+
Usage: #{program} [options] <script.rb> -- <script.rb parameters>
|
178
|
+
EOB
|
179
|
+
opts.separator ""
|
180
|
+
opts.separator "Options:"
|
181
|
+
opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do
|
182
|
+
|annotate|
|
183
|
+
Debugger.annotate = annotate
|
184
|
+
end
|
185
|
+
opts.on("-c", "--client", "Connect to remote debugger") do
|
186
|
+
options.client = true
|
187
|
+
end
|
188
|
+
opts.on("--cport PORT", Integer, "Port used for control commands") do
|
189
|
+
|cport|
|
190
|
+
options.cport = cport
|
191
|
+
end
|
192
|
+
opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true}
|
193
|
+
opts.on("--emacs LEVEL", Integer,
|
194
|
+
"Activates full Emacs support at annotation level LEVEL") do
|
195
|
+
|level|
|
196
|
+
Debugger.annotate = level.to_i
|
197
|
+
ENV['EMACS'] = '1'
|
198
|
+
ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120
|
199
|
+
options.control = false
|
200
|
+
options.quit = false
|
201
|
+
options.post_mortem = true
|
202
|
+
end
|
203
|
+
opts.on('--emacs-basic', 'Activates basic Emacs mode') do
|
204
|
+
ENV['EMACS'] = '1'
|
205
|
+
end
|
206
|
+
opts.on('-h', '--host HOST', 'Host name used for remote debugging') do
|
207
|
+
|host|
|
208
|
+
options.host = host
|
209
|
+
end
|
210
|
+
opts.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path|
|
211
|
+
$LOAD_PATH.unshift(path)
|
212
|
+
end
|
213
|
+
opts.on('--keep-frame-binding', 'Keep frame bindings') do
|
214
|
+
options.frame_bind = true
|
215
|
+
end
|
216
|
+
opts.on('-m', '--post-mortem', 'Activate post-mortem mode') do
|
217
|
+
options.post_mortem = true
|
218
|
+
end
|
219
|
+
opts.on('--no-control', 'Do not automatically start control thread') do
|
220
|
+
options.control = false
|
221
|
+
end
|
222
|
+
opts.on('--no-quit', 'Do not quit when script finishes') do
|
223
|
+
options.quit = false
|
224
|
+
end
|
225
|
+
opts.on('--no-rewrite-program',
|
226
|
+
'Do not set $0 to the program being debugged') do
|
227
|
+
options.no_rewrite_program = true
|
228
|
+
end
|
229
|
+
opts.on('--no-stop', 'Do not stop when script is loaded') do
|
230
|
+
options.stop = false
|
231
|
+
end
|
232
|
+
opts.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do
|
233
|
+
options.nx = true
|
234
|
+
end
|
235
|
+
opts.on('-p', '--port PORT', Integer, 'Port used for remote debugging') do
|
236
|
+
|port|
|
237
|
+
options.port = port
|
238
|
+
end
|
239
|
+
opts.on('-r', '--require SCRIPT', String,
|
240
|
+
'Require the library, before executing your script') do |name|
|
241
|
+
if name == 'debug'
|
242
|
+
puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored."
|
243
|
+
else
|
244
|
+
require name
|
245
|
+
end
|
246
|
+
end
|
247
|
+
opts.on('--restart-script FILE', String,
|
248
|
+
'Name of the script file to run. Erased after read') do
|
249
|
+
|restart_script|
|
250
|
+
options.restart_script = restart_script
|
251
|
+
unless File.exists?(options.restart_script)
|
252
|
+
puts "Script file '#{options.restart_script}' is not found"
|
253
|
+
exit
|
254
|
+
end
|
255
|
+
end
|
256
|
+
opts.on('--script FILE', String, 'Name of the script file to run') do
|
257
|
+
|script|
|
258
|
+
options.script = script
|
259
|
+
unless File.exists?(options.script)
|
260
|
+
puts "Script file '#{options.script}' is not found"
|
261
|
+
exit
|
262
|
+
end
|
263
|
+
end
|
264
|
+
opts.on('-s', '--server', 'Listen for remote connections') do
|
265
|
+
options.server = true
|
266
|
+
end
|
267
|
+
opts.on('-w', '--wait', 'Wait for a client connection, implies -s option') do
|
268
|
+
options.wait = true
|
269
|
+
end
|
270
|
+
opts.on('-x', '--trace', 'Turn on line tracing') {options.tracing = true}
|
271
|
+
opts.separator ''
|
272
|
+
opts.separator 'Common options:'
|
273
|
+
opts.on_tail('--help', 'Show this message') do
|
274
|
+
puts opts
|
275
|
+
exit
|
276
|
+
end
|
277
|
+
opts.on_tail('--version',
|
278
|
+
'Print the version') do
|
279
|
+
puts "ruby-debug #{Debugger::VERSION}"
|
280
|
+
exit
|
281
|
+
end
|
282
|
+
opts.on('--verbose', 'Turn on verbose mode') do
|
283
|
+
$VERBOSE = true
|
284
|
+
options.verbose_long = true
|
285
|
+
end
|
286
|
+
opts.on_tail('-v',
|
287
|
+
'Print version number, then turn on verbose mode') do
|
288
|
+
puts "ruby-debug #{Debugger::VERSION}"
|
289
|
+
$VERBOSE = true
|
290
|
+
end
|
291
|
+
end
|
292
|
+
return opts
|
293
|
+
end
|
294
|
+
|
295
|
+
# What file is used for debugger startup commands.
|
296
|
+
unless defined?(OPTS_INITFILE)
|
297
|
+
if RUBY_PLATFORM =~ /mswin/
|
298
|
+
# Of course MS Windows has to be different
|
299
|
+
OPTS_INITFILE = 'rdbopt.ini'
|
300
|
+
HOME_DIR = (ENV['HOME'] ||
|
301
|
+
ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
|
302
|
+
else
|
303
|
+
OPTS_INITFILE = '.rdboptrc'
|
304
|
+
HOME_DIR = ENV['HOME'].to_s
|
305
|
+
end
|
306
|
+
end
|
307
|
+
begin
|
308
|
+
initfile = File.join(HOME_DIR, OPTS_INITFILE)
|
309
|
+
eval(File.read(initfile)) if
|
310
|
+
File.exist?(initfile)
|
311
|
+
rescue
|
312
|
+
end
|
313
|
+
|
314
|
+
opts = process_options(options)
|
315
|
+
begin
|
316
|
+
if not defined? Debugger::ARGV
|
317
|
+
Debugger::ARGV = ARGV.clone
|
318
|
+
end
|
319
|
+
rdebug_path = File.expand_path($0)
|
320
|
+
if RUBY_PLATFORM =~ /mswin/
|
321
|
+
rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i
|
322
|
+
end
|
323
|
+
Debugger::RDEBUG_SCRIPT = rdebug_path
|
324
|
+
Debugger::RDEBUG_FILE = __FILE__
|
325
|
+
Debugger::INITIAL_DIR = Dir.pwd
|
326
|
+
opts.parse! ARGV
|
327
|
+
rescue StandardError => e
|
328
|
+
puts opts
|
329
|
+
puts
|
330
|
+
puts e.message
|
331
|
+
exit(-1)
|
332
|
+
end
|
333
|
+
|
334
|
+
if options.client
|
335
|
+
Debugger.start_client(options.host, options.port)
|
336
|
+
else
|
337
|
+
if ARGV.empty?
|
338
|
+
exit if $VERBOSE and not options.verbose_long
|
339
|
+
puts opts
|
340
|
+
puts
|
341
|
+
puts 'Must specify a script to run'
|
342
|
+
exit(-1)
|
343
|
+
end
|
344
|
+
|
345
|
+
# save script name
|
346
|
+
prog_script = ARGV.shift
|
347
|
+
prog_script = whence_file(prog_script) unless File.exist?(prog_script)
|
348
|
+
Debugger::PROG_SCRIPT = File.expand_path prog_script
|
349
|
+
|
350
|
+
# install interruption handler
|
351
|
+
trap('INT') { Debugger.interrupt_last }
|
352
|
+
|
353
|
+
# set options
|
354
|
+
Debugger.wait_connection = options.wait
|
355
|
+
Debugger.keep_frame_binding = options.frame_bind
|
356
|
+
|
357
|
+
if options.server
|
358
|
+
# start remote mode
|
359
|
+
Debugger.start_remote(options.host, [options.port, options.cport],
|
360
|
+
options.post_mortem) do
|
361
|
+
# load initrc script
|
362
|
+
Debugger.run_init_script(StringIO.new) unless options.nx
|
363
|
+
end
|
364
|
+
debug_program(options)
|
365
|
+
else
|
366
|
+
# Set up trace hook for debugger
|
367
|
+
Debugger.start
|
368
|
+
# start control thread
|
369
|
+
Debugger.start_control(options.host, options.cport) if options.control
|
370
|
+
|
371
|
+
# load initrc script (e.g. .rdebugrc)
|
372
|
+
Debugger.run_init_script(StringIO.new) unless options.nx
|
373
|
+
|
374
|
+
# run restore-settings startup script if specified
|
375
|
+
if options.restart_script
|
376
|
+
require 'fileutils'
|
377
|
+
Debugger.run_script(options.restart_script)
|
378
|
+
FileUtils.rm(options.restart_script)
|
379
|
+
end
|
380
|
+
|
381
|
+
# run startup script if specified
|
382
|
+
if options.script
|
383
|
+
Debugger.run_script(options.script)
|
384
|
+
end
|
385
|
+
|
386
|
+
# activate post-mortem
|
387
|
+
Debugger.post_mortem if options.post_mortem
|
388
|
+
options.stop = false if options.tracing
|
389
|
+
Debugger.tracing = options.tracing
|
390
|
+
|
391
|
+
if !options.quit
|
392
|
+
if Debugger.started?
|
393
|
+
until Debugger.stop do end
|
394
|
+
end
|
395
|
+
begin
|
396
|
+
debug_program(options)
|
397
|
+
rescue SyntaxError
|
398
|
+
puts $!.backtrace.map{|l| "\t#{l}"}.join("\n")
|
399
|
+
puts "Uncaught Syntax Error\n"
|
400
|
+
rescue
|
401
|
+
print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
|
402
|
+
print "Uncaught exception: #{$!}\n"
|
403
|
+
end
|
404
|
+
print "The program finished.\n" unless
|
405
|
+
Debugger.annotate.to_i > 1 # annotate has its own way
|
406
|
+
interface = Debugger::LocalInterface.new
|
407
|
+
# Not sure if ControlCommandProcessor is really the right
|
408
|
+
# thing to use. CommandProcessor requires a state.
|
409
|
+
processor = Debugger::ControlCommandProcessor.new(interface)
|
410
|
+
processor.process_commands
|
411
|
+
else
|
412
|
+
debug_program(options)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
data/cli/ruby-debug.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'stringio'
|
3
|
+
require 'socket'
|
4
|
+
require 'thread'
|
5
|
+
require 'ruby-debug-base'
|
6
|
+
require_relative 'ruby-debug/processor'
|
7
|
+
|
8
|
+
module Debugger
|
9
|
+
self.handler = CommandProcessor.new
|
10
|
+
|
11
|
+
# the port number used for remote debugging
|
12
|
+
PORT = 8989 unless defined?(PORT)
|
13
|
+
|
14
|
+
# What file is used for debugger startup commands.
|
15
|
+
unless defined?(INITFILE)
|
16
|
+
if RUBY_PLATFORM =~ /mswin/
|
17
|
+
# Of course MS Windows has to be different
|
18
|
+
INITFILE = 'rdebug.ini'
|
19
|
+
HOME_DIR = (ENV['HOME'] ||
|
20
|
+
ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
|
21
|
+
else
|
22
|
+
INITFILE = '.rdebugrc'
|
23
|
+
HOME_DIR = ENV['HOME'].to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# gdb-style annotation mode. Used in GNU Emacs interface
|
29
|
+
attr_accessor :annotate
|
30
|
+
|
31
|
+
# in remote mode, wait for the remote connection
|
32
|
+
attr_accessor :wait_connection
|
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
|
37
|
+
|
38
|
+
attr_reader :thread, :control_thread
|
39
|
+
|
40
|
+
def interface=(value) # :nodoc:
|
41
|
+
handler.interface = value
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Starts a remote debugger.
|
46
|
+
#
|
47
|
+
def start_remote(host = nil, port = PORT, post_mortem = false)
|
48
|
+
return if @thread
|
49
|
+
return if started?
|
50
|
+
|
51
|
+
self.interface = nil
|
52
|
+
start
|
53
|
+
self.post_mortem if post_mortem
|
54
|
+
|
55
|
+
if port.kind_of?(Array)
|
56
|
+
cmd_port, ctrl_port = port
|
57
|
+
else
|
58
|
+
cmd_port, ctrl_port = port, port + 1
|
59
|
+
end
|
60
|
+
|
61
|
+
start_control(host, ctrl_port)
|
62
|
+
|
63
|
+
yield if block_given?
|
64
|
+
|
65
|
+
mutex = Mutex.new
|
66
|
+
proceed = ConditionVariable.new
|
67
|
+
|
68
|
+
@thread = DebugThread.new do
|
69
|
+
server = TCPServer.new(host, cmd_port)
|
70
|
+
while (session = server.accept)
|
71
|
+
self.interface = RemoteInterface.new(session)
|
72
|
+
if wait_connection
|
73
|
+
mutex.synchronize do
|
74
|
+
proceed.signal
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if wait_connection
|
80
|
+
mutex.synchronize do
|
81
|
+
proceed.wait(mutex)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias start_server start_remote
|
86
|
+
|
87
|
+
def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc:
|
88
|
+
raise "Debugger is not started" unless started?
|
89
|
+
return if defined?(@control_thread) && @control_thread
|
90
|
+
@control_thread = DebugThread.new do
|
91
|
+
server = TCPServer.new(host, ctrl_port)
|
92
|
+
while (session = server.accept)
|
93
|
+
interface = RemoteInterface.new(session)
|
94
|
+
processor = ControlCommandProcessor.new(interface)
|
95
|
+
processor.process_commands
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Connects to the remote debugger
|
102
|
+
#
|
103
|
+
def start_client(host = 'localhost', port = PORT)
|
104
|
+
require "socket"
|
105
|
+
interface = Debugger::LocalInterface.new
|
106
|
+
socket = TCPSocket.new(host, port)
|
107
|
+
puts "Connected."
|
108
|
+
|
109
|
+
catch(:exit) do
|
110
|
+
while (line = socket.gets)
|
111
|
+
case line
|
112
|
+
when /^PROMPT (.*)$/
|
113
|
+
input = interface.read_command($1)
|
114
|
+
throw :exit unless input
|
115
|
+
socket.puts input
|
116
|
+
when /^CONFIRM (.*)$/
|
117
|
+
input = interface.confirm($1)
|
118
|
+
throw :exit unless input
|
119
|
+
socket.puts input
|
120
|
+
else
|
121
|
+
print line
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
socket.close
|
126
|
+
end
|
127
|
+
|
128
|
+
# Runs normal debugger initialization scripts
|
129
|
+
# Reads and executes the commands from init file (if any) in the
|
130
|
+
# current working directory. This is only done if the current
|
131
|
+
# directory is different from your home directory. Thus, you can
|
132
|
+
# have more than one init file, one generic in your home directory,
|
133
|
+
# and another, specific to the program you are debugging, in the
|
134
|
+
# directory where you invoke ruby-debug.
|
135
|
+
def run_init_script(out = handler.interface)
|
136
|
+
cwd_script_file = File.expand_path(File.join(".", INITFILE))
|
137
|
+
run_script(cwd_script_file, out) if File.exists?(cwd_script_file)
|
138
|
+
|
139
|
+
home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE))
|
140
|
+
run_script(home_script_file, out) if File.exists?(home_script_file) and
|
141
|
+
cwd_script_file != home_script_file
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Runs a script file
|
146
|
+
#
|
147
|
+
def run_script(file, out = handler.interface, verbose=false)
|
148
|
+
interface = ScriptInterface.new(File.expand_path(file), out)
|
149
|
+
processor = ControlCommandProcessor.new(interface)
|
150
|
+
processor.process_commands(verbose)
|
151
|
+
end
|
152
|
+
end
|
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
|