ruby-debug-ide22 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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