debugger-ide 0.0.1 → 0.0.2
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/Gemfile +4 -0
- data/MIT-LICENSE +24 -0
- data/Rakefile +108 -0
- data/lib/ruby-debug-ide.rb +184 -0
- data/lib/ruby-debug/command.rb +173 -0
- data/lib/ruby-debug/commands/breakpoints.rb +129 -0
- data/lib/ruby-debug/commands/catchpoint.rb +52 -0
- data/lib/ruby-debug/commands/condition.rb +51 -0
- data/lib/ruby-debug/commands/control.rb +129 -0
- data/lib/ruby-debug/commands/enable.rb +203 -0
- data/lib/ruby-debug/commands/eval.rb +64 -0
- data/lib/ruby-debug/commands/frame.rb +155 -0
- data/lib/ruby-debug/commands/inspect.rb +24 -0
- data/lib/ruby-debug/commands/jump.rb +73 -0
- data/lib/ruby-debug/commands/load.rb +18 -0
- data/lib/ruby-debug/commands/pause.rb +32 -0
- data/lib/ruby-debug/commands/set_type.rb +47 -0
- data/lib/ruby-debug/commands/stepping.rb +108 -0
- data/lib/ruby-debug/commands/threads.rb +153 -0
- data/lib/ruby-debug/commands/variables.rb +142 -0
- data/lib/ruby-debug/event_processor.rb +74 -0
- data/lib/ruby-debug/helper.rb +33 -0
- data/lib/ruby-debug/interface.rb +39 -0
- data/lib/ruby-debug/printers.rb +2 -0
- data/lib/ruby-debug/processor.rb +152 -0
- data/lib/ruby-debug/xml_printer.rb +268 -0
- metadata +28 -2
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
The file lib/classic-debug.rb is based on the debug.rb file from Ruby
|
2
|
+
project.
|
3
|
+
|
4
|
+
Copyright (c) 2007-2008, debug-commons team
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
desc 'Default: run unit tests.'
|
9
|
+
task :default => [:test]
|
10
|
+
|
11
|
+
# ------- Default Package ----------
|
12
|
+
RUBY_DEBUG_IDE_VERSION = "0.4.13"
|
13
|
+
|
14
|
+
FILES = FileList[
|
15
|
+
# 'CHANGES',
|
16
|
+
# 'ChangeLog',
|
17
|
+
# 'ChangeLog.archive',
|
18
|
+
'MIT-LICENSE',
|
19
|
+
'Rakefile',
|
20
|
+
'bin/*',
|
21
|
+
'lib/**/*'
|
22
|
+
# 'test/**/*'
|
23
|
+
]
|
24
|
+
|
25
|
+
ide_spec = Gem::Specification.new do |spec|
|
26
|
+
spec.name = "ruby-debug-ide19"
|
27
|
+
|
28
|
+
spec.homepage = "http://rubyforge.org/projects/ruby-debug19"
|
29
|
+
spec.summary = "IDE interface for ruby-debug."
|
30
|
+
spec.description = <<-EOF
|
31
|
+
An interface which glues ruby-debug to IDEs like Eclipse (RDT) and NetBeans.
|
32
|
+
EOF
|
33
|
+
|
34
|
+
spec.version = RUBY_DEBUG_IDE_VERSION
|
35
|
+
|
36
|
+
spec.author = "Markus Barchfeld, Martin Krauskopf, Mark Moseley"
|
37
|
+
spec.email = "mark@fast-software.com"
|
38
|
+
spec.platform = Gem::Platform::RUBY
|
39
|
+
spec.require_path = "lib"
|
40
|
+
spec.bindir = "bin"
|
41
|
+
spec.executables = ["rdebug-ide"]
|
42
|
+
spec.files = FILES.to_a
|
43
|
+
spec.add_dependency("debugger", "~> 1.2.1")
|
44
|
+
|
45
|
+
spec.required_ruby_version = '>= 1.8.2'
|
46
|
+
spec.date = DateTime.now
|
47
|
+
spec.rubyforge_project = 'debug-commons'
|
48
|
+
|
49
|
+
# rdoc
|
50
|
+
spec.has_rdoc = false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Rake task to build the default package
|
54
|
+
Rake::GemPackageTask.new(ide_spec) do |pkg|
|
55
|
+
pkg.need_tar = true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Unit tests
|
59
|
+
Rake::TestTask.new do |t|
|
60
|
+
t.libs << "test"
|
61
|
+
t.libs << "test-base"
|
62
|
+
t.pattern = 'test/*_test.rb'
|
63
|
+
t.verbose = true
|
64
|
+
t.warning = false
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
desc "Create a GNU-style ChangeLog via svn2cl"
|
69
|
+
task :ChangeLog do
|
70
|
+
system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/debug-commons/ruby-debug-ide/trunk -o ChangeLog")
|
71
|
+
end
|
72
|
+
|
73
|
+
#desc "Publish ruby-debug to RubyForge."
|
74
|
+
#task :publish do
|
75
|
+
# require 'rake/contrib/sshpublisher'
|
76
|
+
#
|
77
|
+
# # Get ruby-debug path
|
78
|
+
# ruby_debug_path = File.expand_path(File.dirname(__FILE__))
|
79
|
+
#
|
80
|
+
# publisher = Rake::SshDirPublisher.new("kent@rubyforge.org",
|
81
|
+
# "/var/www/gforge-projects/ruby-debug", ruby_debug_path)
|
82
|
+
#end
|
83
|
+
#
|
84
|
+
#desc "Clear temp files"
|
85
|
+
#task :clean do
|
86
|
+
# cd "ext" do
|
87
|
+
# if File.exists?("Makefile")
|
88
|
+
# sh "make clean"
|
89
|
+
# rm "Makefile"
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
#end
|
93
|
+
#
|
94
|
+
## --------- RDoc Documentation ------
|
95
|
+
#desc "Generate rdoc documentation"
|
96
|
+
#Rake::RDocTask.new("rdoc") do |rdoc|
|
97
|
+
# rdoc.rdoc_dir = 'doc'
|
98
|
+
# rdoc.title = "ruby-debug"
|
99
|
+
# # Show source inline with line numbers
|
100
|
+
# rdoc.options << "--inline-source" << "--line-numbers"
|
101
|
+
# # Make the readme file the start page for the generated html
|
102
|
+
# rdoc.options << '--main' << 'README'
|
103
|
+
# rdoc.rdoc_files.include('bin/**/*',
|
104
|
+
# 'lib/**/*.rb',
|
105
|
+
# 'ext/**/ruby_debug.c',
|
106
|
+
# 'README',
|
107
|
+
# 'LICENSE')
|
108
|
+
#end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'stringio'
|
3
|
+
require "socket"
|
4
|
+
require 'thread'
|
5
|
+
require 'debugger'
|
6
|
+
if RUBY_VERSION < "1.9"
|
7
|
+
require 'ruby-debug/xml_printer'
|
8
|
+
require 'ruby-debug/processor'
|
9
|
+
require 'ruby-debug/event_processor'
|
10
|
+
else
|
11
|
+
require_relative 'ruby-debug/xml_printer'
|
12
|
+
require_relative 'ruby-debug/processor'
|
13
|
+
require_relative 'ruby-debug/event_processor'
|
14
|
+
end
|
15
|
+
|
16
|
+
module Debugger
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# Prints to the stderr using printf(*args) if debug logging flag (-d) is on.
|
20
|
+
def print_debug(*args)
|
21
|
+
if Debugger.cli_debug
|
22
|
+
$stderr.printf(*args)
|
23
|
+
$stderr.printf("\n")
|
24
|
+
$stderr.flush
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def without_stderr
|
29
|
+
begin
|
30
|
+
if RUBY_PLATFORM =~ /(win32|mingw32)/
|
31
|
+
$stderr = File.open('NUL', 'w')
|
32
|
+
else
|
33
|
+
$stderr = File.open('/dev/null', 'w')
|
34
|
+
end
|
35
|
+
yield
|
36
|
+
ensure
|
37
|
+
$stderr = STDERR
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
class Context
|
44
|
+
def interrupt
|
45
|
+
self.stop_next = 1
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def event_processor
|
51
|
+
Debugger.event_processor
|
52
|
+
end
|
53
|
+
|
54
|
+
def at_breakpoint(breakpoint)
|
55
|
+
event_processor.at_breakpoint(self, breakpoint)
|
56
|
+
end
|
57
|
+
|
58
|
+
def at_catchpoint(excpt)
|
59
|
+
event_processor.at_catchpoint(self, excpt)
|
60
|
+
end
|
61
|
+
|
62
|
+
def at_tracing(file, line)
|
63
|
+
if event_processor
|
64
|
+
event_processor.at_tracing(self, file, line)
|
65
|
+
else
|
66
|
+
Debugger::print_debug "trace: location=\"%s:%s\", threadId=%d", file, line, self.thnum
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def at_line(file, line)
|
71
|
+
event_processor.at_line(self, file, line)
|
72
|
+
end
|
73
|
+
|
74
|
+
def at_return(file, line)
|
75
|
+
event_processor.at_return(self, file, line)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
|
81
|
+
attr_accessor :event_processor, :cli_debug, :xml_debug
|
82
|
+
attr_reader :control_thread
|
83
|
+
|
84
|
+
#
|
85
|
+
# Interrupts the current thread
|
86
|
+
#
|
87
|
+
def interrupt
|
88
|
+
current_context.interrupt
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Interrupts the last debugged thread
|
93
|
+
#
|
94
|
+
def interrupt_last
|
95
|
+
skip do
|
96
|
+
if context = last_context
|
97
|
+
return nil unless context.thread.alive?
|
98
|
+
context.interrupt
|
99
|
+
end
|
100
|
+
context
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def start_server(host = nil, port = 1234)
|
105
|
+
start
|
106
|
+
start_control(host, port)
|
107
|
+
end
|
108
|
+
|
109
|
+
def debug_program(options)
|
110
|
+
start_server(options.host, options.port)
|
111
|
+
|
112
|
+
raise "Control thread did not start (#{@control_thread}}" unless @control_thread && @control_thread.alive?
|
113
|
+
|
114
|
+
@mutex = Mutex.new
|
115
|
+
@proceed = ConditionVariable.new
|
116
|
+
|
117
|
+
# wait for 'start' command
|
118
|
+
@mutex.synchronize do
|
119
|
+
@proceed.wait(@mutex)
|
120
|
+
end
|
121
|
+
|
122
|
+
bt = debug_load(Debugger::PROG_SCRIPT, options.stop, options.load_mode)
|
123
|
+
if bt
|
124
|
+
$stderr.print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
|
125
|
+
$stderr.print "Uncaught exception: #{bt}\n"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def run_prog_script
|
130
|
+
return unless @mutex
|
131
|
+
@mutex.synchronize do
|
132
|
+
@proceed.signal
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def start_control(host, port)
|
137
|
+
return if @control_thread
|
138
|
+
@control_thread = DebugThread.new do
|
139
|
+
begin
|
140
|
+
$stderr.printf "Fast Debugger (ruby-debug-ide 0.4.9) listens on #{host}:#{port}\n"
|
141
|
+
# 127.0.0.1 seemingly works with all systems and with IPv6 as well.
|
142
|
+
# "localhost" and nil on have problems on some systems.
|
143
|
+
host ||= '127.0.0.1'
|
144
|
+
server = TCPServer.new(host, port)
|
145
|
+
while (session = server.accept)
|
146
|
+
begin
|
147
|
+
interface = RemoteInterface.new(session)
|
148
|
+
@event_processor = EventProcessor.new(interface)
|
149
|
+
ControlCommandProcessor.new(interface).process_commands
|
150
|
+
rescue StandardError, ScriptError => ex
|
151
|
+
$stderr.printf "Exception in DebugThread loop: #{ex}\n"
|
152
|
+
exit 1
|
153
|
+
end
|
154
|
+
end
|
155
|
+
rescue
|
156
|
+
$stderr.printf "Exception in DebugThread: #$!\n"
|
157
|
+
exit 2
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
class Exception # :nodoc:
|
165
|
+
attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
|
166
|
+
end
|
167
|
+
|
168
|
+
module Kernel
|
169
|
+
#
|
170
|
+
# Stops the current thread after a number of _steps_ made.
|
171
|
+
#
|
172
|
+
def debugger(steps = 1)
|
173
|
+
Debugger.current_context.stop_next = steps
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Returns a binding of n-th call frame
|
178
|
+
#
|
179
|
+
def binding_n(n = 0)
|
180
|
+
Debugger.current_context.frame_binding[n+1]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
if RUBY_VERSION < "1.9"
|
2
|
+
require 'ruby-debug/helper'
|
3
|
+
else
|
4
|
+
require_relative 'helper'
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module Debugger
|
9
|
+
|
10
|
+
class Command # :nodoc:
|
11
|
+
SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
|
12
|
+
defined?(SubcmdStruct)
|
13
|
+
|
14
|
+
# Find param in subcmds. param id downcased and can be abbreviated
|
15
|
+
# to the minimum length listed in the subcommands
|
16
|
+
def find(subcmds, param)
|
17
|
+
param.downcase!
|
18
|
+
for try_subcmd in subcmds do
|
19
|
+
if (param.size >= try_subcmd.min) and
|
20
|
+
(try_subcmd.name[0..param.size-1] == param)
|
21
|
+
return try_subcmd
|
22
|
+
end
|
23
|
+
end
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def commands
|
29
|
+
@commands ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
DEF_OPTIONS = {
|
33
|
+
:event => true,
|
34
|
+
:control => false,
|
35
|
+
:unknown => false,
|
36
|
+
:need_context => false,
|
37
|
+
}
|
38
|
+
|
39
|
+
def inherited(klass)
|
40
|
+
DEF_OPTIONS.each do |o, v|
|
41
|
+
klass.options[o] = v if klass.options[o].nil?
|
42
|
+
end
|
43
|
+
commands << klass
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_commands
|
47
|
+
dir = File.dirname(__FILE__)
|
48
|
+
Dir[File.join(dir, 'commands', '*')].each do |file|
|
49
|
+
require file if file =~ /\.rb$/
|
50
|
+
end
|
51
|
+
Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
|
52
|
+
include mod
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def method_missing(meth, *args, &block)
|
57
|
+
if meth.to_s =~ /^(.+?)=$/
|
58
|
+
@options[$1.intern] = args.first
|
59
|
+
else
|
60
|
+
if @options.has_key?(meth)
|
61
|
+
@options[meth]
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def options
|
69
|
+
@options ||= {}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize(state, printer)
|
74
|
+
@state, @printer = state, printer
|
75
|
+
end
|
76
|
+
|
77
|
+
def match(input)
|
78
|
+
@match = regexp.match(input)
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def method_missing(meth, *args, &block)
|
84
|
+
if @printer.respond_to? meth
|
85
|
+
@printer.send meth, *args, &block
|
86
|
+
else
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# FIXME: use delegate?
|
92
|
+
def errmsg(*args)
|
93
|
+
@printer.print_error(*args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def print(*args)
|
97
|
+
@state.print(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
# see Timeout::timeout, the difference is that we must use a DebugThread
|
101
|
+
# because every other thread would be halted when the event hook is reached
|
102
|
+
# in ruby-debug.c
|
103
|
+
def timeout(sec)
|
104
|
+
return yield if sec == nil or sec.zero?
|
105
|
+
if Thread.respond_to?(:critical) and Thread.critical
|
106
|
+
raise ThreadError, "timeout within critical session"
|
107
|
+
end
|
108
|
+
begin
|
109
|
+
x = Thread.current
|
110
|
+
y = DebugThread.start {
|
111
|
+
sleep sec
|
112
|
+
x.raise StandardError, "Timeout: evaluation took longer than #{sec} seconds." if x.alive?
|
113
|
+
}
|
114
|
+
yield sec
|
115
|
+
ensure
|
116
|
+
y.kill if y and y.alive?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def debug_eval(str, b = get_binding)
|
121
|
+
begin
|
122
|
+
str = str.to_s
|
123
|
+
max_time = 10
|
124
|
+
to_inspect = str.gsub(/\\n/, "\n")
|
125
|
+
@printer.print_debug("Evaluating with timeout after %i sec", max_time)
|
126
|
+
timeout(max_time) do
|
127
|
+
if RUBY_VERSION < "1.9"
|
128
|
+
eval(to_inspect, b)
|
129
|
+
else
|
130
|
+
Debugger::without_stderr { eval(to_inspect, b) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
rescue StandardError, ScriptError => e
|
134
|
+
@printer.print_exception(e, @state.binding)
|
135
|
+
throw :debug_error
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def debug_silent_eval(str)
|
140
|
+
begin
|
141
|
+
str = str.to_s
|
142
|
+
eval(str, get_binding)
|
143
|
+
rescue StandardError, ScriptError
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def hbinding(hash)
|
149
|
+
code = hash.keys.map{|k| "#{k} = hash['#{k}']"}.join(';') + ';binding'
|
150
|
+
if obj = @state.context.frame_self(@state.frame_pos)
|
151
|
+
obj.instance_eval code
|
152
|
+
else
|
153
|
+
eval code
|
154
|
+
end
|
155
|
+
end
|
156
|
+
private :hbinding
|
157
|
+
|
158
|
+
def get_binding
|
159
|
+
binding = @state.context.frame_binding(@state.frame_pos)
|
160
|
+
binding || hbinding(@state.context.frame_locals(@state.frame_pos))
|
161
|
+
end
|
162
|
+
|
163
|
+
def line_at(file, line)
|
164
|
+
Debugger.line_at(file, line)
|
165
|
+
end
|
166
|
+
|
167
|
+
def get_context(thnum)
|
168
|
+
Debugger.contexts.find{|c| c.thnum == thnum}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
Command.load_commands
|
173
|
+
end
|