ruby-debug-ide-docker 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +75 -0
  3. data/ChangeLog.archive +1073 -0
  4. data/ChangeLog.md +594 -0
  5. data/Gemfile +28 -0
  6. data/MIT-LICENSE +24 -0
  7. data/Rakefile +42 -0
  8. data/bin/gdb_wrapper +96 -0
  9. data/bin/rdebug-ide +183 -0
  10. data/ext/mkrf_conf.rb +48 -0
  11. data/lib/ruby-debug-ide.rb +173 -0
  12. data/lib/ruby-debug-ide/attach/debugger_loader.rb +20 -0
  13. data/lib/ruby-debug-ide/attach/gdb.rb +73 -0
  14. data/lib/ruby-debug-ide/attach/lldb.rb +71 -0
  15. data/lib/ruby-debug-ide/attach/native_debugger.rb +133 -0
  16. data/lib/ruby-debug-ide/attach/process_thread.rb +54 -0
  17. data/lib/ruby-debug-ide/attach/util.rb +115 -0
  18. data/lib/ruby-debug-ide/command.rb +177 -0
  19. data/lib/ruby-debug-ide/commands/breakpoints.rb +128 -0
  20. data/lib/ruby-debug-ide/commands/catchpoint.rb +64 -0
  21. data/lib/ruby-debug-ide/commands/condition.rb +51 -0
  22. data/lib/ruby-debug-ide/commands/control.rb +158 -0
  23. data/lib/ruby-debug-ide/commands/enable.rb +203 -0
  24. data/lib/ruby-debug-ide/commands/eval.rb +64 -0
  25. data/lib/ruby-debug-ide/commands/expression_info.rb +71 -0
  26. data/lib/ruby-debug-ide/commands/file_filtering.rb +107 -0
  27. data/lib/ruby-debug-ide/commands/frame.rb +155 -0
  28. data/lib/ruby-debug-ide/commands/inspect.rb +25 -0
  29. data/lib/ruby-debug-ide/commands/jump.rb +73 -0
  30. data/lib/ruby-debug-ide/commands/load.rb +18 -0
  31. data/lib/ruby-debug-ide/commands/pause.rb +33 -0
  32. data/lib/ruby-debug-ide/commands/set_type.rb +47 -0
  33. data/lib/ruby-debug-ide/commands/stepping.rb +108 -0
  34. data/lib/ruby-debug-ide/commands/threads.rb +178 -0
  35. data/lib/ruby-debug-ide/commands/variables.rb +154 -0
  36. data/lib/ruby-debug-ide/event_processor.rb +71 -0
  37. data/lib/ruby-debug-ide/greeter.rb +40 -0
  38. data/lib/ruby-debug-ide/helper.rb +33 -0
  39. data/lib/ruby-debug-ide/ide_processor.rb +155 -0
  40. data/lib/ruby-debug-ide/interface.rb +45 -0
  41. data/lib/ruby-debug-ide/multiprocess.rb +23 -0
  42. data/lib/ruby-debug-ide/multiprocess/monkey.rb +47 -0
  43. data/lib/ruby-debug-ide/multiprocess/pre_child.rb +67 -0
  44. data/lib/ruby-debug-ide/multiprocess/starter.rb +11 -0
  45. data/lib/ruby-debug-ide/multiprocess/unmonkey.rb +31 -0
  46. data/lib/ruby-debug-ide/version.rb +3 -0
  47. data/lib/ruby-debug-ide/xml_printer.rb +545 -0
  48. data/ruby-debug-ide-docker.gemspec +51 -0
  49. metadata +110 -0
data/Gemfile ADDED
@@ -0,0 +1,28 @@
1
+ source "http://rubygems.org"
2
+
3
+ # @param [Array<String>] versions compatible ruby versions
4
+ # @return [Array<String>] an array with mri platforms of given versions
5
+ def mries(*versions)
6
+ versions.flat_map do |v|
7
+ %w(ruby mingw x64_mingw)
8
+ .map { |platform| "#{platform}_#{v}".to_sym unless platform == "x64_mingw" && v < "2.0" }
9
+ .delete_if &:nil?
10
+ end
11
+ end
12
+
13
+ gem "ruby-debug-base", :platforms => [:jruby, *mries('18')]
14
+ gem "ruby-debug-base19x", ">= 0.11.32", :platforms => mries('19')
15
+ if RUBY_VERSION && RUBY_VERSION >= "2.0"
16
+ gem "debase", "~> 0.2.2", :platforms => mries('20', '21', '22', '23', '24', '25')
17
+ end
18
+
19
+ gemspec
20
+
21
+ group :development do
22
+ gem "bundler"
23
+ end
24
+
25
+ group :test do
26
+ gem "test-unit"
27
+ end
28
+
@@ -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
+
@@ -0,0 +1,42 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Default: run unit tests.'
5
+ task :default => [:test]
6
+
7
+ # Unit tests
8
+ Rake::TestTask.new do |t|
9
+ t.libs << "test"
10
+ t.libs << "test-base"
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ t.warning = false
14
+ end
15
+
16
+ desc "Create a ChangeLog"
17
+ # simple rake task to output a changelog between two commits, tags ...
18
+ # output is formatted simply, commits are grouped under each author name
19
+ desc "generate changelog with nice clean output"
20
+ task :changelog, :since_c, :until_c do |t,args|
21
+ since_c = args[:since_c] || `git tag | head -1`.chomp
22
+ until_c = args[:until_c]
23
+ cmd=`git log --pretty='format:%ci::%an <%ae>::%s::%H' #{since_c}..#{until_c}`
24
+
25
+ entries = Hash.new
26
+ changelog_content = String.new
27
+
28
+ cmd.split("\n").each do |entry|
29
+ date, author, subject, hash = entry.chomp.split("::")
30
+ entries[author] = Array.new unless entries[author]
31
+ day = date.split(" ").first
32
+ entries[author] << "#{subject} (#{hash})" unless subject =~ /Merge/
33
+ end
34
+
35
+ # generate clean output
36
+ entries.keys.each do |author|
37
+ changelog_content += author + "\n"
38
+ entries[author].reverse.each { |entry| changelog_content += " * #{entry}\n" }
39
+ end
40
+
41
+ puts changelog_content
42
+ end
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'thread'
5
+ require 'ostruct'
6
+
7
+ $stdout.sync = true
8
+ $stderr.sync = true
9
+
10
+ options = OpenStruct.new(
11
+ 'pid' => nil,
12
+ 'sdk_path' => nil,
13
+ 'uid' => nil,
14
+ 'gems_to_include' => []
15
+ )
16
+
17
+ module DebugPrinter
18
+
19
+ class << self
20
+ attr_accessor :cli_debug
21
+
22
+ def print_debug(msg)
23
+ if DebugPrinter.cli_debug
24
+ $stderr.puts msg
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ DebugPrinter.cli_debug = ARGV.include? '--debug'
32
+
33
+ opts = OptionParser.new do |opts|
34
+ # TODO need some banner
35
+ opts.banner = <<EOB
36
+ Some useful banner.
37
+ EOB
38
+
39
+ opts.on('--pid PID', 'pid of process you want to attach to for debugging') do |pid|
40
+ options.pid = pid
41
+ end
42
+
43
+ opts.on('--ruby-path RUBY_PATH', 'path to ruby interpreter') do |ruby_path|
44
+ options.ruby_path = ruby_path
45
+ end
46
+
47
+ opts.on('--uid UID', 'uid which this process should set after executing gdb attach') do |uid|
48
+ options.uid = uid
49
+ end
50
+
51
+ opts.on('--include-gem GEM_LIB_PATH', 'lib of gem to include') do |gem_lib_path|
52
+ options.gems_to_include << gem_lib_path
53
+ end
54
+ end
55
+
56
+ opts.parse! ARGV
57
+
58
+ unless options.pid
59
+ $stderr.puts 'You should specify PID of process you want to attach to'
60
+ exit 1
61
+ end
62
+
63
+ unless options.ruby_path
64
+ $stderr.puts 'You should specify path to the ruby interpreter'
65
+ exit 1
66
+ end
67
+
68
+ argv = '["' + ARGV * '", "' + '"]'
69
+ child_argv = '["' + ARGV * '", "' + "', '--ignore-port" + '"]'
70
+ debugger_loader_path = File.expand_path(File.dirname(__FILE__)) + '/../lib/ruby-debug-ide/attach/debugger_loader'
71
+
72
+ options.gems_to_include.each do |gem_path|
73
+ $LOAD_PATH.unshift(gem_path) unless $LOAD_PATH.include?(gem_path)
74
+ end
75
+
76
+ require 'ruby-debug-ide/greeter'
77
+ Debugger::print_greeting_msg($stdout, nil, nil)
78
+
79
+ require 'ruby-debug-ide/attach/util'
80
+ require 'ruby-debug-ide/attach/native_debugger'
81
+ require 'ruby-debug-ide/attach/process_thread'
82
+
83
+
84
+ child_pids = get_child_pids(options.pid.to_s)
85
+ attach_threads = Array.new
86
+ attach_threads << attach_and_return_thread(options, options.pid, debugger_loader_path, argv)
87
+
88
+ attach_threads << child_pids.map {|pid| attach_and_return_thread(options, pid, debugger_loader_path, child_argv)}
89
+
90
+
91
+ attach_threads.each {|thread| thread.join}
92
+ if options.uid
93
+ DebugPrinter.print_debug("changing current uid from #{Process.uid} to #{options.uid}")
94
+ Process::Sys.setuid(options.uid.to_i)
95
+ end
96
+ sleep
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+ require "ostruct"
5
+ if RUBY_VERSION < "1.9"
6
+ require 'ruby-debug-ide'
7
+ else
8
+ require_relative '../lib/ruby-debug-ide'
9
+ end
10
+
11
+ $stdout.sync=true
12
+
13
+ options = OpenStruct.new(
14
+ 'frame_bind' => false,
15
+ 'host' => nil,
16
+ 'load_mode' => false,
17
+ 'port' => 1234,
18
+ 'stop' => false,
19
+ 'tracing' => false,
20
+ 'int_handler' => true,
21
+ 'dispatcher_port' => -1,
22
+ 'evaluation_timeout' => 10,
23
+ 'trace_to_s' => false,
24
+ 'debugger_memory_limit' => 10,
25
+ 'inspect_time_limit' => 100,
26
+ 'rm_protocol_extensions' => false,
27
+ 'catchpoint_deleted_event' => false,
28
+ 'value_as_nested_element' => false,
29
+ 'attach_mode' => false,
30
+ 'cli_debug' => false
31
+ )
32
+
33
+ opts = OptionParser.new do |opts|
34
+ opts.banner = <<EOB
35
+ Using ruby-debug-base #{Debugger::VERSION}
36
+ Usage: rdebug-ide is supposed to be called from RDT, NetBeans, RubyMine, or
37
+ the IntelliJ IDEA Ruby plugin. The command line interface to
38
+ ruby-debug is rdebug.
39
+ EOB
40
+ opts.separator ""
41
+ opts.separator "Options:"
42
+
43
+ opts.on("-h", "--host HOST", "Host name used for remote debugging") {|host| options.host = host}
44
+ opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|port| options.port = port}
45
+ opts.on("--dispatcher-port PORT", Integer, "Port used for multi-process debugging dispatcher") do |dp|
46
+ options.dispatcher_port = dp
47
+ end
48
+ opts.on('--evaluation-timeout TIMEOUT', Integer,'evaluation timeout in seconds (default: 10)') do |timeout|
49
+ options.evaluation_timeout = timeout
50
+ end
51
+ opts.on("--evaluation-control", "trace to_s evaluation") {options.trace_to_s = true}
52
+
53
+ opts.on("-m", "--memory-limit LIMIT", Integer, "evaluation memory limit in mb (default: 10)") do |limit|
54
+ if defined?(JRUBY_VERSION) || RUBY_VERSION < '2.0'
55
+ $stderr.puts "Evaluation memory limit is ineffective in JRuby and MRI < 2.0"
56
+ limit = 0
57
+ end
58
+ options.debugger_memory_limit = limit
59
+ options.trace_to_s ||= limit > 0
60
+ end
61
+
62
+ opts.on("-t", "--time-limit LIMIT", Integer, "evaluation time limit in milliseconds (default: 100)") do |limit|
63
+ options.inspect_time_limit = limit
64
+ options.trace_to_s ||= limit > 0
65
+ end
66
+
67
+ opts.on('--stop', 'stop when the script is loaded') {options.stop = true}
68
+ opts.on("-x", "--trace", "turn on line tracing") {options.tracing = true}
69
+ opts.on("-l", "--load-mode", "load mode (experimental)") {options.load_mode = true}
70
+ opts.on("-d", "--debug", "Debug self - prints information for debugging ruby-debug itself") do
71
+ Debugger.cli_debug = true
72
+ options.cli_debug = true
73
+ end
74
+ opts.on("--xml-debug", "Debug self - sends information <message>s for debugging ruby-debug itself") do
75
+ Debugger.xml_debug = true
76
+ end
77
+ opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path|
78
+ $LOAD_PATH.unshift(path)
79
+ end
80
+ opts.on("--attach-mode", "Tells that rdebug-ide is working in attach mode") do
81
+ options.attach_mode = true
82
+ end
83
+ opts.on("--ignore-port", "Generate another port") do
84
+ options.ignore_port = true
85
+ end
86
+ opts.on("--keep-frame-binding", "Keep frame bindings") {options.frame_bind = true}
87
+ opts.on("--disable-int-handler", "Disables interrupt signal handler") {options.int_handler = false}
88
+ opts.on("--rubymine-protocol-extensions", "Enable all RubyMine-specific incompatible protocol extensions") do
89
+ options.rm_protocol_extensions = true
90
+ end
91
+ opts.on("--catchpoint-deleted-event", "Enable chatchpointDeleted event") do
92
+ options.catchpoint_deleted_event = true
93
+ end
94
+ opts.on("--value-as-nested-element", "Allow to pass variable's value as nested element instead of attribute") do
95
+ options.value_as_nested_element = true
96
+ end
97
+ opts.separator ""
98
+ opts.separator "Common options:"
99
+ opts.on_tail("-v", "--version", "Show version") do
100
+ puts "Using ruby-debug-base #{Debugger::VERSION}"
101
+ exit
102
+ end
103
+ end
104
+
105
+ begin
106
+ Debugger::ARGV = ARGV.clone
107
+ rdebug_path = File.expand_path($0)
108
+ if RUBY_PLATFORM =~ /mswin/
109
+ rdebug_path += ".cmd" unless rdebug_path =~ /\.cmd$/i
110
+ end
111
+ Debugger::RDEBUG_SCRIPT = rdebug_path
112
+ opts.parse! ARGV
113
+ rescue StandardError => e
114
+ puts opts
115
+ puts
116
+ puts e.message
117
+ exit(1)
118
+ end
119
+
120
+ if ARGV.empty? && !options.attach_mode
121
+ puts opts
122
+ puts
123
+ puts "Must specify a script to run"
124
+ exit(1)
125
+ end
126
+
127
+ # save script name
128
+ if !options.attach_mode
129
+ Debugger::PROG_SCRIPT = ARGV.shift
130
+ else
131
+ Debugger::PROG_SCRIPT = $0
132
+ end
133
+
134
+ if options.dispatcher_port != -1
135
+ ENV['IDE_PROCESS_DISPATCHER'] = options.dispatcher_port.to_s
136
+ if RUBY_VERSION < "1.9"
137
+ lib_path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
138
+ $: << lib_path unless $:.include? lib_path
139
+ require 'ruby-debug-ide/multiprocess'
140
+ else
141
+ require_relative '../lib/ruby-debug-ide/multiprocess'
142
+ end
143
+ Debugger::MultiProcess.do_monkey
144
+
145
+ ENV['DEBUGGER_STORED_RUBYLIB'] = ENV['RUBYLIB']
146
+ old_opts = ENV['RUBYOPT'] || ''
147
+ starter = "-r#{File.expand_path(File.dirname(__FILE__))}/../lib/ruby-debug-ide/multiprocess/starter"
148
+ unless old_opts.include? starter
149
+ ENV['RUBYOPT'] = starter
150
+ ENV['RUBYOPT'] += " #{old_opts}" if old_opts != ''
151
+ end
152
+ ENV['DEBUGGER_CLI_DEBUG'] = Debugger.cli_debug.to_s
153
+ end
154
+
155
+ if options.int_handler
156
+ # install interruption handler
157
+ trap('INT') { Debugger.interrupt_last }
158
+ end
159
+
160
+ # set options
161
+ Debugger.keep_frame_binding = options.frame_bind
162
+ Debugger.tracing = options.tracing
163
+ Debugger.evaluation_timeout = options.evaluation_timeout
164
+ Debugger.trace_to_s = options.trace_to_s && (options.debugger_memory_limit > 0 || options.inspect_time_limit > 0)
165
+ Debugger.debugger_memory_limit = options.debugger_memory_limit
166
+ Debugger.inspect_time_limit = options.inspect_time_limit
167
+ Debugger.catchpoint_deleted_event = options.catchpoint_deleted_event || options.rm_protocol_extensions
168
+ Debugger.value_as_nested_element = options.value_as_nested_element || options.rm_protocol_extensions
169
+
170
+ if options.attach_mode
171
+ if Debugger::FRONT_END == "debase"
172
+ Debugger.init_variables
173
+ end
174
+
175
+ Debugger::MultiProcess::pre_child(options)
176
+
177
+ if Debugger::FRONT_END == "debase"
178
+ Debugger.setup_tracepoints
179
+ Debugger.prepare_context
180
+ end
181
+ else
182
+ Debugger.debug_program(options)
183
+ end
@@ -0,0 +1,48 @@
1
+ jruby = defined?(JRUBY_VERSION) || (defined?(RUBY_ENGINE) && 'jruby' == RUBY_ENGINE)
2
+ rbx = defined?(RUBY_ENGINE) && 'rbx' == RUBY_ENGINE
3
+
4
+ def already_installed(dep)
5
+ !Gem::DependencyInstaller.new(:domain => :local).find_gems_with_sources(dep).empty? ||
6
+ !Gem::DependencyInstaller.new(:domain => :local,:prerelease => true).find_gems_with_sources(dep).empty?
7
+ end
8
+
9
+ unless jruby || rbx
10
+ require 'rubygems'
11
+ require 'rubygems/command.rb'
12
+ require 'rubygems/dependency.rb'
13
+ require 'rubygems/dependency_installer.rb'
14
+
15
+ begin
16
+ Gem::Command.build_args = ARGV
17
+ rescue NoMethodError
18
+ end
19
+
20
+ if RUBY_VERSION < "1.9"
21
+ dep = Gem::Dependency.new("ruby-debug-base", '>=0.10.4')
22
+ elsif RUBY_VERSION < '2.0'
23
+ dep = Gem::Dependency.new("ruby-debug-base19x", '>=0.11.30.pre15')
24
+ else
25
+ dep = Gem::Dependency.new("debase", '> 0')
26
+ end
27
+
28
+ begin
29
+ puts "Installing base gem"
30
+ inst = Gem::DependencyInstaller.new :prerelease => dep.prerelease?
31
+ inst.install dep
32
+ rescue
33
+ begin
34
+ inst = Gem::DependencyInstaller.new(:prerelease => true)
35
+ inst.install dep
36
+ rescue Exception => e
37
+ puts e
38
+ puts e.backtrace.join "\n "
39
+ exit(1)
40
+ end
41
+ end unless dep.nil? || already_installed(dep)
42
+ end
43
+
44
+ # create dummy rakefile to indicate success
45
+ f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w")
46
+ f.write("task :default\n")
47
+ f.close
48
+
@@ -0,0 +1,173 @@
1
+ require 'pp'
2
+ require 'stringio'
3
+ require "socket"
4
+ require 'thread'
5
+ if RUBY_VERSION < '2.0' || defined?(JRUBY_VERSION)
6
+ require 'ruby-debug-base'
7
+ Debugger::FRONT_END = "ruby-debug-base"
8
+ else
9
+ require 'debase'
10
+ Debugger::FRONT_END = "debase"
11
+ end
12
+
13
+ require 'ruby-debug-ide/greeter'
14
+ require 'ruby-debug-ide/xml_printer'
15
+ require 'ruby-debug-ide/ide_processor'
16
+ require 'ruby-debug-ide/event_processor'
17
+
18
+ module Debugger
19
+
20
+ class << self
21
+ # Prints to the stderr using printf(*args) if debug logging flag (-d) is on.
22
+ def print_debug(*args)
23
+ if Debugger.cli_debug
24
+ $stderr.printf("#{Process.pid}: ")
25
+ $stderr.printf(*args)
26
+ $stderr.printf("\n")
27
+ $stderr.flush
28
+ end
29
+ end
30
+
31
+ def cleanup_backtrace(backtrace)
32
+ cleared = []
33
+ return cleared unless backtrace
34
+ backtrace.each do |line|
35
+ if line.index(File.expand_path(File.dirname(__FILE__) + "/..")) == 0
36
+ next
37
+ end
38
+ if line.index("-e:1") == 0
39
+ break
40
+ end
41
+ cleared << line
42
+ end
43
+ cleared
44
+ end
45
+
46
+ attr_accessor :attached
47
+ attr_accessor :cli_debug, :xml_debug, :evaluation_timeout
48
+ attr_accessor :trace_to_s, :debugger_memory_limit, :inspect_time_limit
49
+ attr_accessor :control_thread
50
+ attr_reader :interface
51
+ # protocol extensions
52
+ attr_accessor :catchpoint_deleted_event, :value_as_nested_element
53
+
54
+
55
+ #
56
+ # Interrupts the last debugged thread
57
+ #
58
+ def interrupt_last
59
+ skip do
60
+ if context = last_context
61
+ return nil unless context.thread.alive?
62
+ context.interrupt
63
+ end
64
+ context
65
+ end
66
+ end
67
+
68
+ def start_server(host = nil, port = 1234, notify_dispatcher = false)
69
+ return if started?
70
+ start
71
+ start_control(host, port, notify_dispatcher)
72
+ end
73
+
74
+ def prepare_debugger(options)
75
+ @mutex = Mutex.new
76
+ @proceed = ConditionVariable.new
77
+
78
+ start_server(options.host, options.port, options.notify_dispatcher)
79
+
80
+ raise "Control thread did not start (#{@control_thread}}" unless @control_thread && @control_thread.alive?
81
+
82
+ # wait for 'start' command
83
+ @mutex.synchronize do
84
+ @proceed.wait(@mutex)
85
+ end
86
+ end
87
+
88
+ def debug_program(options)
89
+ prepare_debugger(options)
90
+
91
+ abs_prog_script = File.expand_path(Debugger::PROG_SCRIPT)
92
+ bt = debug_load(abs_prog_script, options.stop, options.load_mode)
93
+ if bt && !bt.is_a?(SystemExit)
94
+ $stderr.print "Uncaught exception: #{bt}\n"
95
+ $stderr.print Debugger.cleanup_backtrace(bt.backtrace).map{|l| "\t#{l}"}.join("\n"), "\n"
96
+ end
97
+ end
98
+
99
+ def run_prog_script
100
+ return unless @mutex
101
+ @mutex.synchronize do
102
+ @proceed.signal
103
+ end
104
+ end
105
+
106
+ def start_control(host, port, notify_dispatcher)
107
+ raise "Debugger is not started" unless started?
108
+ return if @control_thread
109
+ @control_thread = DebugThread.new do
110
+ begin
111
+ # 127.0.0.1 seemingly works with all systems and with IPv6 as well.
112
+ # "localhost" and nil have problems on some systems.
113
+ host ||= '127.0.0.1'
114
+ server = TCPServer.new(host, port)
115
+ print_greeting_msg($stderr, host, port) if defined? IDE_VERSION
116
+ notify_dispatcher(port) if notify_dispatcher
117
+ while (session = server.accept)
118
+ $stderr.puts "Connected from #{session.peeraddr[2]}" if Debugger.cli_debug
119
+ dispatcher = ENV['IDE_PROCESS_DISPATCHER']
120
+ if dispatcher
121
+ ENV['IDE_PROCESS_DISPATCHER'] = "#{session.peeraddr[2]}:#{dispatcher}" unless dispatcher.include?(":")
122
+ ENV['DEBUGGER_HOST'] = host
123
+ end
124
+ begin
125
+ @interface = RemoteInterface.new(session)
126
+ self.handler = EventProcessor.new(interface)
127
+ IdeControlCommandProcessor.new(interface).process_commands
128
+ rescue StandardError, ScriptError => ex
129
+ bt = ex.backtrace
130
+ $stderr.printf "#{Process.pid}: Exception in DebugThread loop: #{ex.message}(#{ex.class})\nBacktrace:\n#{bt ? bt.join("\n from: ") : "<none>"}\n"
131
+ exit 1
132
+ end
133
+ end
134
+ rescue
135
+ bt = $!.backtrace
136
+ $stderr.printf "Fatal exception in DebugThread loop: #{$!.message}\nBacktrace:\n#{bt ? bt.join("\n from: ") : "<none>"}\n"
137
+ exit 2
138
+ end
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+
145
+ def notify_dispatcher(port)
146
+ return unless ENV['IDE_PROCESS_DISPATCHER']
147
+ acceptor_host, acceptor_port = ENV['IDE_PROCESS_DISPATCHER'].split(":")
148
+ acceptor_host, acceptor_port = '127.0.0.1', acceptor_host unless acceptor_port
149
+ connected = false
150
+
151
+ 3.times do |i|
152
+ begin
153
+ s = TCPSocket.open(acceptor_host, acceptor_port)
154
+ s.print(port)
155
+ s.close
156
+ connected = true
157
+ print_debug "Ide process dispatcher notified about sub-debugger which listens on #{port}\n"
158
+ return
159
+ rescue => bt
160
+ $stderr.puts "#{Process.pid}: connection failed(#{i+1})"
161
+ $stderr.puts "Exception: #{bt}"
162
+ $stderr.puts bt.backtrace.map { |l| "\t#{l}" }.join("\n")
163
+ sleep 0.3
164
+ end unless connected
165
+ end
166
+ end
167
+
168
+ end
169
+
170
+ class Exception # :nodoc:
171
+ attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
172
+ end
173
+ end