ruby-debug-ide22 0.7.4 → 0.7.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +75 -75
  3. data/ChangeLog.archive +1073 -1073
  4. data/ChangeLog.md +594 -594
  5. data/Gemfile +38 -38
  6. data/MIT-LICENSE +24 -24
  7. data/Rakefile +92 -92
  8. data/bin/gdb_wrapper +96 -96
  9. data/bin/rdebug-ide +200 -200
  10. data/ext/mkrf_conf.rb +44 -44
  11. data/lib/ruby-debug-ide/attach/debugger_loader.rb +20 -20
  12. data/lib/ruby-debug-ide/attach/gdb.rb +73 -73
  13. data/lib/ruby-debug-ide/attach/lldb.rb +71 -71
  14. data/lib/ruby-debug-ide/attach/native_debugger.rb +133 -133
  15. data/lib/ruby-debug-ide/attach/process_thread.rb +54 -54
  16. data/lib/ruby-debug-ide/attach/util.rb +114 -114
  17. data/lib/ruby-debug-ide/command.rb +187 -187
  18. data/lib/ruby-debug-ide/commands/breakpoints.rb +128 -128
  19. data/lib/ruby-debug-ide/commands/catchpoint.rb +64 -64
  20. data/lib/ruby-debug-ide/commands/condition.rb +51 -51
  21. data/lib/ruby-debug-ide/commands/control.rb +164 -158
  22. data/lib/ruby-debug-ide/commands/enable.rb +203 -203
  23. data/lib/ruby-debug-ide/commands/eval.rb +64 -64
  24. data/lib/ruby-debug-ide/commands/expression_info.rb +71 -71
  25. data/lib/ruby-debug-ide/commands/file_filtering.rb +106 -106
  26. data/lib/ruby-debug-ide/commands/frame.rb +155 -155
  27. data/lib/ruby-debug-ide/commands/inspect.rb +25 -25
  28. data/lib/ruby-debug-ide/commands/load.rb +17 -17
  29. data/lib/ruby-debug-ide/commands/stepping.rb +108 -108
  30. data/lib/ruby-debug-ide/commands/threads.rb +178 -178
  31. data/lib/ruby-debug-ide/commands/variables.rb +154 -154
  32. data/lib/ruby-debug-ide/event_processor.rb +71 -71
  33. data/lib/ruby-debug-ide/greeter.rb +42 -42
  34. data/lib/ruby-debug-ide/helper.rb +33 -33
  35. data/lib/ruby-debug-ide/ide_processor.rb +155 -155
  36. data/lib/ruby-debug-ide/interface.rb +47 -45
  37. data/lib/ruby-debug-ide/multiprocess/monkey.rb +46 -46
  38. data/lib/ruby-debug-ide/multiprocess/pre_child.rb +58 -58
  39. data/lib/ruby-debug-ide/multiprocess/starter.rb +10 -10
  40. data/lib/ruby-debug-ide/multiprocess/unmonkey.rb +30 -30
  41. data/lib/ruby-debug-ide/multiprocess.rb +22 -22
  42. data/lib/ruby-debug-ide/thread_alias.rb +26 -26
  43. data/lib/ruby-debug-ide/version.rb +3 -3
  44. data/lib/ruby-debug-ide/xml_printer.rb +570 -570
  45. data/lib/ruby-debug-ide.rb +230 -228
  46. data/ruby-debug-ide.gemspec +47 -47
  47. metadata +4 -4
@@ -1,115 +1,115 @@
1
- require 'ruby-debug-ide/attach/lldb'
2
- require 'ruby-debug-ide/attach/gdb'
3
- require 'socket'
4
- require 'set'
5
-
6
- def attach_and_return_thread(options, pid, debugger_loader_path, argv)
7
- Thread.new(argv) do |argv|
8
-
9
- debugger = choose_debugger(options.ruby_path, pid, options.gems_to_include, debugger_loader_path, argv)
10
-
11
- trap('INT') do
12
- unless debugger.exited?
13
- $stderr.puts "backtraces for threads:\n\n"
14
- process_threads = debugger.process_threads
15
- if process_threads
16
- process_threads.each do |thread|
17
- $stderr.puts "#{thread.thread_info}\n#{thread.last_bt}\n\n"
18
- end
19
- end
20
- debugger.exit
21
- end
22
- exit!
23
- end
24
-
25
- debugger.attach_to_process
26
- debugger.set_flags
27
-
28
- if debugger.check_already_under_debug
29
- $stderr.puts "Process #{debugger.pid} is already under debug"
30
- debugger.exit
31
- exit!
32
- end
33
-
34
- should_check_threads_state = true
35
-
36
- while should_check_threads_state
37
- should_check_threads_state = false
38
- debugger.update_threads.each do |thread|
39
- thread.switch
40
- while thread.need_finish_frame
41
- should_check_threads_state = true
42
- thread.finish
43
- end
44
- end
45
- end
46
-
47
- debugger.wait_line_event
48
- debugger.load_debugger
49
- debugger.exit
50
- end
51
- end
52
-
53
- def get_child_pids(pid)
54
- return [] unless command_exists 'pgrep'
55
-
56
- pids = Array.new
57
-
58
- q = Queue.new
59
- q.push(pid)
60
-
61
- until q.empty? do
62
- pid = q.pop
63
-
64
- pipe = IO.popen("pgrep -P #{pid}")
65
-
66
- pipe.readlines.each do |child|
67
- child_pid = child.strip.to_i
68
- q.push(child_pid)
69
- pids << child_pid
70
- end
71
- end
72
-
73
- filter_ruby_processes(pids)
74
- end
75
-
76
- def filter_ruby_processes(pids)
77
- pipe = IO.popen(%Q(lsof -c ruby | awk '{print $2 ":" $9}' | grep -E 'bin/ruby([[:digit:]]+\.?)*$'))
78
-
79
- ruby_processes = Set.new
80
-
81
- pipe.readlines.each do |process|
82
- pid = process.split(/:/).first
83
- ruby_processes.add(pid.to_i)
84
- end
85
-
86
- ruby_processes_pids, non_ruby_processes_pids = pids.partition {|pid| ruby_processes.include? pid}
87
-
88
- DebugPrinter.print_debug("The following child processes was added to attach: #{ruby_processes_pids.join(', ')}") unless ruby_processes_pids.empty?
89
- DebugPrinter.print_debug("The following child are not ruby processes: #{non_ruby_processes_pids.join(', ')}") unless non_ruby_processes_pids.empty?
90
-
91
- ruby_processes_pids
92
- end
93
-
94
- def command_exists(command)
95
- checking_command = "checking command #{command} for existence\n"
96
- `command -v #{command} >/dev/null 2>&1 || { exit 1; }`
97
- if $?.exitstatus != 0
98
- DebugPrinter.print_debug("#{checking_command}command does not exist.")
99
- else
100
- DebugPrinter.print_debug("#{checking_command}command does exist.")
101
- end
102
- $?.exitstatus == 0
103
- end
104
-
105
- def choose_debugger(ruby_path, pid, gems_to_include, debugger_loader_path, argv)
106
- if command_exists(LLDB.to_s)
107
- debugger = LLDB.new(ruby_path, pid, '--no-lldbinit', gems_to_include, debugger_loader_path, argv)
108
- elsif command_exists(GDB.to_s)
109
- debugger = GDB.new(ruby_path, pid, '-nh -nx', gems_to_include, debugger_loader_path, argv)
110
- else
111
- raise 'Neither gdb nor lldb was found. Aborting.'
112
- end
113
-
114
- debugger
1
+ require 'ruby-debug-ide/attach/lldb'
2
+ require 'ruby-debug-ide/attach/gdb'
3
+ require 'socket'
4
+ require 'set'
5
+
6
+ def attach_and_return_thread(options, pid, debugger_loader_path, argv)
7
+ Thread.new(argv) do |argv|
8
+
9
+ debugger = choose_debugger(options.ruby_path, pid, options.gems_to_include, debugger_loader_path, argv)
10
+
11
+ trap('INT') do
12
+ unless debugger.exited?
13
+ $stderr.puts "backtraces for threads:\n\n"
14
+ process_threads = debugger.process_threads
15
+ if process_threads
16
+ process_threads.each do |thread|
17
+ $stderr.puts "#{thread.thread_info}\n#{thread.last_bt}\n\n"
18
+ end
19
+ end
20
+ debugger.exit
21
+ end
22
+ exit!
23
+ end
24
+
25
+ debugger.attach_to_process
26
+ debugger.set_flags
27
+
28
+ if debugger.check_already_under_debug
29
+ $stderr.puts "Process #{debugger.pid} is already under debug"
30
+ debugger.exit
31
+ exit!
32
+ end
33
+
34
+ should_check_threads_state = true
35
+
36
+ while should_check_threads_state
37
+ should_check_threads_state = false
38
+ debugger.update_threads.each do |thread|
39
+ thread.switch
40
+ while thread.need_finish_frame
41
+ should_check_threads_state = true
42
+ thread.finish
43
+ end
44
+ end
45
+ end
46
+
47
+ debugger.wait_line_event
48
+ debugger.load_debugger
49
+ debugger.exit
50
+ end
51
+ end
52
+
53
+ def get_child_pids(pid)
54
+ return [] unless command_exists 'pgrep'
55
+
56
+ pids = Array.new
57
+
58
+ q = Queue.new
59
+ q.push(pid)
60
+
61
+ until q.empty? do
62
+ pid = q.pop
63
+
64
+ pipe = IO.popen("pgrep -P #{pid}")
65
+
66
+ pipe.readlines.each do |child|
67
+ child_pid = child.strip.to_i
68
+ q.push(child_pid)
69
+ pids << child_pid
70
+ end
71
+ end
72
+
73
+ filter_ruby_processes(pids)
74
+ end
75
+
76
+ def filter_ruby_processes(pids)
77
+ pipe = IO.popen(%Q(lsof -c ruby | awk '{print $2 ":" $9}' | grep -E 'bin/ruby([[:digit:]]+\.?)*$'))
78
+
79
+ ruby_processes = Set.new
80
+
81
+ pipe.readlines.each do |process|
82
+ pid = process.split(/:/).first
83
+ ruby_processes.add(pid.to_i)
84
+ end
85
+
86
+ ruby_processes_pids, non_ruby_processes_pids = pids.partition {|pid| ruby_processes.include? pid}
87
+
88
+ DebugPrinter.print_debug("The following child processes was added to attach: #{ruby_processes_pids.join(', ')}") unless ruby_processes_pids.empty?
89
+ DebugPrinter.print_debug("The following child are not ruby processes: #{non_ruby_processes_pids.join(', ')}") unless non_ruby_processes_pids.empty?
90
+
91
+ ruby_processes_pids
92
+ end
93
+
94
+ def command_exists(command)
95
+ checking_command = "checking command #{command} for existence\n"
96
+ `command -v #{command} >/dev/null 2>&1 || { exit 1; }`
97
+ if $?.exitstatus != 0
98
+ DebugPrinter.print_debug("#{checking_command}command does not exist.")
99
+ else
100
+ DebugPrinter.print_debug("#{checking_command}command does exist.")
101
+ end
102
+ $?.exitstatus == 0
103
+ end
104
+
105
+ def choose_debugger(ruby_path, pid, gems_to_include, debugger_loader_path, argv)
106
+ if command_exists(LLDB.to_s)
107
+ debugger = LLDB.new(ruby_path, pid, '--no-lldbinit', gems_to_include, debugger_loader_path, argv)
108
+ elsif command_exists(GDB.to_s)
109
+ debugger = GDB.new(ruby_path, pid, '-nh -nx', gems_to_include, debugger_loader_path, argv)
110
+ else
111
+ raise 'Neither gdb nor lldb was found. Aborting.'
112
+ end
113
+
114
+ debugger
115
115
  end
@@ -1,187 +1,187 @@
1
- if RUBY_VERSION < '2.0' || defined?(JRUBY_VERSION)
2
- require 'ruby-debug-base'
3
- else
4
- require 'debase'
5
- end
6
-
7
- require 'ruby-debug-ide/thread_alias'
8
- require 'ruby-debug-ide/helper'
9
- require 'delegate'
10
-
11
- module Debugger
12
-
13
- class Command < SimpleDelegator # :nodoc:
14
- SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
15
- defined?(SubcmdStruct)
16
-
17
- # Find param in subcmds. param id downcased and can be abbreviated
18
- # to the minimum length listed in the subcommands
19
- def find(subcmds, param)
20
- param.downcase!
21
- for try_subcmd in subcmds do
22
- if (param.size >= try_subcmd.min) and
23
- (try_subcmd.name[0..param.size-1] == param)
24
- return try_subcmd
25
- end
26
- end
27
- return nil
28
- end
29
-
30
- class << self
31
- def commands
32
- @commands ||= []
33
- end
34
-
35
- DEF_OPTIONS = {
36
- :event => true,
37
- :control => false,
38
- :unknown => false,
39
- :need_context => false,
40
- }
41
-
42
- def inherited(klass)
43
- DEF_OPTIONS.each do |o, v|
44
- klass.options[o] = v if klass.options[o].nil?
45
- end
46
- commands << klass
47
- end
48
-
49
- def load_commands
50
- dir = File.dirname(__FILE__)
51
- Dir[File.join(dir, 'commands', '*')].each do |file|
52
- require file if file =~ /\.rb$/
53
- end
54
- Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
55
- include mod
56
- end
57
- end
58
-
59
- def method_missing(meth, *args, &block)
60
- if meth.to_s =~ /^(.+?)=$/
61
- @options[$1.intern] = args.first
62
- else
63
- if @options.has_key?(meth)
64
- @options[meth]
65
- else
66
- super
67
- end
68
- end
69
- end
70
-
71
- def options
72
- @options ||= {}
73
- end
74
-
75
- def unescape_incoming(str)
76
- str.gsub(/((?:^|[^\\])(?:\\\\)*)((?:\\n)+)/) do |_|
77
- $1 + "\n" * ($2.size / 2)
78
- end.gsub(/\\\\/, '\\')
79
- end
80
-
81
- def file_filter_supported?
82
- defined?(Debugger.file_filter)
83
- end
84
- end
85
-
86
- def initialize(state, printer)
87
- @state, @printer = state, printer
88
- super @printer
89
- end
90
-
91
- def match(input)
92
- @match = regexp.match(input)
93
- end
94
-
95
- protected
96
-
97
- def errmsg(*args)
98
- @printer.print_error(*args)
99
- end
100
-
101
- def print(*args)
102
- @state.print(*args)
103
- end
104
-
105
- # see Timeout::timeout, the difference is that we must use a DebugThread
106
- # because every other thread would be halted when the event hook is reached
107
- # in ruby-debug.c
108
- def timeout(sec)
109
- return yield if sec == nil or sec.zero?
110
- if Thread.respond_to?(:critical) and Thread.critical
111
- raise ThreadError, "timeout within critical session"
112
- end
113
- begin
114
- x = Thread.current
115
- y = DebugThread.start {
116
- sleep sec
117
- x.raise StandardError, "Timeout: evaluation took longer than #{sec} seconds." if x.alive?
118
- }
119
- yield sec
120
- ensure
121
- y.kill if y and y.alive?
122
- end
123
- end
124
-
125
- def debug_eval(str, b = get_binding)
126
- begin
127
- str = str.to_s
128
- str.force_encoding('UTF-8') if(RUBY_VERSION >= '2.0')
129
- to_inspect = Command.unescape_incoming(str)
130
- max_time = Debugger.evaluation_timeout
131
- @printer.print_debug("Evaluating %s with timeout after %i sec", str, max_time)
132
-
133
- Debugger::TimeoutHandler.do_thread_alias
134
-
135
- eval_result = nil
136
-
137
- timeout(max_time) do
138
- eval_result = eval(to_inspect, b)
139
- end
140
-
141
- Debugger::TimeoutHandler.undo_thread_alias
142
-
143
- return eval_result
144
- rescue StandardError, ScriptError => e
145
- @printer.print_exception(e, @state.binding)
146
- throw :debug_error
147
- end
148
- end
149
-
150
- def debug_silent_eval(str)
151
- begin
152
- str = str.to_s
153
- eval(str, get_binding)
154
- rescue StandardError, ScriptError
155
- nil
156
- end
157
- end
158
-
159
- def get_binding
160
- @state.context.frame_binding(@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
-
171
- def realpath(filename)
172
- is_dir = filename.end_with?(File::SEPARATOR)
173
- if filename.index(File::SEPARATOR) || File::ALT_SEPARATOR && filename.index(File::ALT_SEPARATOR)
174
- filename = File.expand_path(filename)
175
- end
176
- if (RUBY_VERSION < '1.9') || (RbConfig::CONFIG['host_os'] =~ /mswin/)
177
- filename
178
- else
179
- filename = File.realpath(filename) rescue filename
180
- filename = filename + File::SEPARATOR if is_dir && !filename.end_with?(File::SEPARATOR)
181
- filename
182
- end
183
- end
184
- end
185
-
186
- Command.load_commands
187
- end
1
+ if RUBY_VERSION < '2.0' || defined?(JRUBY_VERSION)
2
+ require 'ruby-debug-base'
3
+ else
4
+ require 'debase'
5
+ end
6
+
7
+ require 'ruby-debug-ide/thread_alias'
8
+ require 'ruby-debug-ide/helper'
9
+ require 'delegate'
10
+
11
+ module Debugger
12
+
13
+ class Command < SimpleDelegator # :nodoc:
14
+ SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
15
+ defined?(SubcmdStruct)
16
+
17
+ # Find param in subcmds. param id downcased and can be abbreviated
18
+ # to the minimum length listed in the subcommands
19
+ def find(subcmds, param)
20
+ param.downcase!
21
+ for try_subcmd in subcmds do
22
+ if (param.size >= try_subcmd.min) and
23
+ (try_subcmd.name[0..param.size-1] == param)
24
+ return try_subcmd
25
+ end
26
+ end
27
+ return nil
28
+ end
29
+
30
+ class << self
31
+ def commands
32
+ @commands ||= []
33
+ end
34
+
35
+ DEF_OPTIONS = {
36
+ :event => true,
37
+ :control => false,
38
+ :unknown => false,
39
+ :need_context => false,
40
+ }
41
+
42
+ def inherited(klass)
43
+ DEF_OPTIONS.each do |o, v|
44
+ klass.options[o] = v if klass.options[o].nil?
45
+ end
46
+ commands << klass
47
+ end
48
+
49
+ def load_commands
50
+ dir = File.dirname(__FILE__)
51
+ Dir[File.join(dir, 'commands', '*')].each do |file|
52
+ require file if file =~ /\.rb$/
53
+ end
54
+ Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
55
+ include mod
56
+ end
57
+ end
58
+
59
+ def method_missing(meth, *args, &block)
60
+ if meth.to_s =~ /^(.+?)=$/
61
+ @options[$1.intern] = args.first
62
+ else
63
+ if @options.has_key?(meth)
64
+ @options[meth]
65
+ else
66
+ super
67
+ end
68
+ end
69
+ end
70
+
71
+ def options
72
+ @options ||= {}
73
+ end
74
+
75
+ def unescape_incoming(str)
76
+ str.gsub(/((?:^|[^\\])(?:\\\\)*)((?:\\n)+)/) do |_|
77
+ $1 + "\n" * ($2.size / 2)
78
+ end.gsub(/\\\\/, '\\')
79
+ end
80
+
81
+ def file_filter_supported?
82
+ defined?(Debugger.file_filter)
83
+ end
84
+ end
85
+
86
+ def initialize(state, printer)
87
+ @state, @printer = state, printer
88
+ super @printer
89
+ end
90
+
91
+ def match(input)
92
+ @match = regexp.match(input)
93
+ end
94
+
95
+ protected
96
+
97
+ def errmsg(*args)
98
+ @printer.print_error(*args)
99
+ end
100
+
101
+ def print(*args)
102
+ @state.print(*args)
103
+ end
104
+
105
+ # see Timeout::timeout, the difference is that we must use a DebugThread
106
+ # because every other thread would be halted when the event hook is reached
107
+ # in ruby-debug.c
108
+ def timeout(sec)
109
+ return yield if sec == nil or sec.zero?
110
+ if Thread.respond_to?(:critical) and Thread.critical
111
+ raise ThreadError, "timeout within critical session"
112
+ end
113
+ begin
114
+ x = Thread.current
115
+ y = DebugThread.start {
116
+ sleep sec
117
+ x.raise StandardError, "Timeout: evaluation took longer than #{sec} seconds." if x.alive?
118
+ }
119
+ yield sec
120
+ ensure
121
+ y.kill if y and y.alive?
122
+ end
123
+ end
124
+
125
+ def debug_eval(str, b = get_binding)
126
+ begin
127
+ str = str.to_s
128
+ str.force_encoding('UTF-8') if(RUBY_VERSION >= '2.0')
129
+ to_inspect = Command.unescape_incoming(str)
130
+ max_time = Debugger.evaluation_timeout
131
+ @printer.print_debug("Evaluating %s with timeout after %i sec", str, max_time)
132
+
133
+ Debugger::TimeoutHandler.do_thread_alias
134
+
135
+ eval_result = nil
136
+
137
+ timeout(max_time) do
138
+ eval_result = eval(to_inspect, b)
139
+ end
140
+
141
+ Debugger::TimeoutHandler.undo_thread_alias
142
+
143
+ return eval_result
144
+ rescue StandardError, ScriptError => e
145
+ @printer.print_exception(e, @state.binding)
146
+ throw :debug_error
147
+ end
148
+ end
149
+
150
+ def debug_silent_eval(str)
151
+ begin
152
+ str = str.to_s
153
+ eval(str, get_binding)
154
+ rescue StandardError, ScriptError
155
+ nil
156
+ end
157
+ end
158
+
159
+ def get_binding
160
+ @state.context.frame_binding(@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
+
171
+ def realpath(filename)
172
+ is_dir = filename.end_with?(File::SEPARATOR)
173
+ if filename.index(File::SEPARATOR) || File::ALT_SEPARATOR && filename.index(File::ALT_SEPARATOR)
174
+ filename = File.expand_path(filename)
175
+ end
176
+ if (RUBY_VERSION < '1.9') || (RbConfig::CONFIG['host_os'] =~ /mswin/)
177
+ filename
178
+ else
179
+ filename = File.realpath(filename) rescue filename
180
+ filename = filename + File::SEPARATOR if is_dir && !filename.end_with?(File::SEPARATOR)
181
+ filename
182
+ end
183
+ end
184
+ end
185
+
186
+ Command.load_commands
187
+ end