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
@@ -0,0 +1,154 @@
1
+ module Debugger
2
+ class VarConstantCommand < Command # :nodoc:
3
+ def regexp
4
+ /^\s*v(?:ar)?\s+c(?:onst(?:ant)?)?\s+/
5
+ end
6
+
7
+ def execute
8
+ obj = debug_eval(@match.post_match)
9
+ unless obj.kind_of? Module
10
+ print_msg "Should be Class/Module: %s", @match.post_match
11
+ else
12
+ print_variables(obj.constants, "constant") do |var|
13
+ obj.const_get(var)
14
+ end
15
+ end
16
+ end
17
+
18
+ class << self
19
+ def help_command
20
+ 'var'
21
+ end
22
+
23
+ def help(cmd)
24
+ %{
25
+ v[ar] c[onst] <object>\t\tshow constants of object
26
+ }
27
+ end
28
+ end
29
+ end
30
+
31
+ class VarGlobalCommand < Command # :nodoc:
32
+ def regexp
33
+ /^\s*v(?:ar)?\s+g(?:lobal)?\s*$/
34
+ end
35
+
36
+ def execute
37
+ globals = []
38
+ if RUBY_VERSION < "1.9"
39
+ globals = global_variables - ['$=', '$IGNORECASE']
40
+ else
41
+ globals = global_variables - [:$KCODE, :$-K, :$=, :$IGNORECASE, :$FILENAME]
42
+ end
43
+ print_variables(globals, 'global') do |var|
44
+ debug_eval(var)
45
+ end
46
+ end
47
+
48
+ class << self
49
+ def help_command
50
+ 'var'
51
+ end
52
+
53
+ def help(cmd)
54
+ %{
55
+ v[ar] g[lobal]\t\t\tshow global variables
56
+ }
57
+ end
58
+ end
59
+ end
60
+
61
+ class VarInstanceCommand < Command # :nodoc:
62
+ # TODO: try to find out a way to use Kernel.binding for Rubinius
63
+ # ::Kernel.binding doesn't for for ruby 1.8 (see RUBY-14679)
64
+ BINDING_COMMAND = (defined?(Rubinius) || RUBY_VERSION < '1.9') ? 'binding' : '::Kernel.binding'
65
+
66
+ def regexp
67
+ # id will be read as first match, name as post match
68
+ /^\s*v(?:ar)?\s+i(?:nstance)?\s+((?:[\\+-]0x)[\dabcdef]+)?/
69
+ end
70
+
71
+ def execute
72
+ if (@match[1])
73
+ obj = ObjectSpace._id2ref(@match[1].hex) rescue nil
74
+
75
+ unless obj
76
+ print_element("variables")
77
+ @printer.print_msg("Unknown object id : %s", @match[1])
78
+ end
79
+ else
80
+ obj = debug_eval(@match.post_match)
81
+ end
82
+ return unless obj
83
+ if obj.is_a?(Array)
84
+ print_array(obj)
85
+ elsif obj.is_a?(Hash)
86
+ print_hash(obj)
87
+ elsif obj.is_a?(String)
88
+ print_string(obj)
89
+ else
90
+ print_element("variables") do
91
+ # instance variables
92
+ kind = 'instance'
93
+ inst_vars = obj.instance_variables
94
+ instance_binding = obj.instance_eval(BINDING_COMMAND)
95
+ # print self at top position
96
+ print_variable('self', debug_eval('self', instance_binding), kind) if inst_vars.include?('self')
97
+ inst_vars.sort.each do |var|
98
+ print_variable(var, debug_eval(var, instance_binding), kind) unless var == 'self'
99
+ end
100
+
101
+ # class variables
102
+ class_binding = obj.class.class_eval(BINDING_COMMAND)
103
+ obj.class.class_variables.sort.each do |var|
104
+ print_variable(var, debug_eval(var, class_binding), 'class')
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ class << self
111
+ def help_command
112
+ 'var'
113
+ end
114
+
115
+ def help(cmd)
116
+ %{
117
+ v[ar] i[nstance] <object>\tshow instance variables of object, object can be given by its id or an expression
118
+ }
119
+ end
120
+ end
121
+ end
122
+
123
+ class VarLocalCommand < Command # :nodoc:
124
+ def regexp
125
+ /^\s*v(?:ar)?\s+l(?:ocal)?\s*$/
126
+ end
127
+
128
+ def execute
129
+ locals = @state.context.frame_locals(@state.frame_pos)
130
+ _self = @state.context.frame_self(@state.frame_pos)
131
+ begin
132
+ locals['self'] = _self unless TOPLEVEL_BINDING.eval('self') == _self
133
+ rescue => ex
134
+ locals['self'] = "<Cannot evaluate self>"
135
+ $stderr << "Cannot evaluate self\n#{ex.class.name}: #{ex.message}\n #{ex.backtrace.join("\n ")}"
136
+ end
137
+ print_variables(locals.keys, 'local') do |var|
138
+ locals[var]
139
+ end
140
+ end
141
+
142
+ class << self
143
+ def help_command
144
+ 'var'
145
+ end
146
+
147
+ def help(cmd)
148
+ %{
149
+ v[ar] l[ocal]\t\t\tshow local variables
150
+ }
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,71 @@
1
+ require 'ruby-debug-ide/xml_printer'
2
+
3
+ module Debugger
4
+
5
+ class EventProcessor
6
+
7
+ attr_accessor :line, :file, :context
8
+
9
+ def initialize(interface)
10
+ @printer = XmlPrinter.new(interface)
11
+ @interface = interface
12
+ @line = nil
13
+ @file = nil
14
+ @last_breakpoint = nil
15
+ end
16
+
17
+ def at_breakpoint(context, breakpoint)
18
+ raise "@last_breakpoint supposed to be nil. is #{@last_breakpoint}" if @last_breakpoint
19
+ # at_breakpoint is immediately followed by #at_line event in
20
+ # ruby-debug-base. So postpone breakpoint printing until #at_line.
21
+ @last_breakpoint = breakpoint
22
+ end
23
+
24
+ def at_catchpoint(context, excpt)
25
+ @printer.print_catchpoint(excpt)
26
+ end
27
+
28
+ def at_tracing(context, file, line)
29
+ @printer.print_trace(context, file, line)
30
+ end
31
+
32
+ def at_line(context, file, line)
33
+ @printer.print_at_line(context, file, line) if context.nil? || context.stop_reason == :step
34
+ line_event(context, file, line)
35
+ end
36
+
37
+ def at_return(context, file, line)
38
+ @printer.print_at_line(context, file, line)
39
+ context.stop_frame = -1
40
+ line_event(context, file, line)
41
+ end
42
+
43
+ def line_event(context, file, line)
44
+ @line = line
45
+ @file = file
46
+ @context = context
47
+ if @last_breakpoint
48
+ # followed after #at_breakpoint in the same thread. Print breakpoint
49
+ # now when @line, @file and @context are correctly set to prevent race
50
+ # condition with `control thread'.
51
+ n = Debugger.breakpoints.index(@last_breakpoint) + 1
52
+ @printer.print_breakpoint n, @last_breakpoint
53
+ @last_breakpoint = nil
54
+ end
55
+ raise "DebuggerThread are not supposed to be traced (#{context.thread})" if context.thread.is_a?(Debugger::DebugThread)
56
+ @printer.print_debug("Stopping Thread %s (%s)", context.thread.to_s, Process.pid.to_s)
57
+ @printer.print_debug("Threads equal: %s", Thread.current == context.thread)
58
+ IdeCommandProcessor.new(@interface).process_commands
59
+ InspectCommand.clear_references
60
+ @printer.print_debug("Resumed Thread %s", context.thread.to_s)
61
+ @line = nil
62
+ @file = nil
63
+ @context = nil
64
+ end
65
+
66
+ def at_line?
67
+ @line
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,40 @@
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/version'
8
+ require 'ruby-debug-ide/ide_processor'
9
+
10
+ module Debugger
11
+
12
+ class << self
13
+ def print_greeting_msg(stream, host, port)
14
+ base_gem_name = if defined?(JRUBY_VERSION) || RUBY_VERSION < '1.9.0'
15
+ 'ruby-debug-base'
16
+ elsif RUBY_VERSION < '2.0.0'
17
+ 'ruby-debug-base19x'
18
+ else
19
+ 'debase'
20
+ end
21
+
22
+ file_filtering_support = if Command.file_filter_supported?
23
+ 'supported'
24
+ else
25
+ 'not supported'
26
+ end
27
+
28
+ if host && port
29
+ listens_on = " listens on #{host}:#{port}\n"
30
+ else
31
+ listens_on = "\n"
32
+ end
33
+
34
+ msg = "Fast Debugger (ruby-debug-ide #{IDE_VERSION}, #{base_gem_name} #{VERSION}, file filtering is #{file_filtering_support})" + listens_on
35
+
36
+ stream.printf msg
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,33 @@
1
+ module Debugger
2
+
3
+ module ParseFunctions
4
+ # Parse 'str' of command 'cmd' as an integer between
5
+ # min and max. If either min or max is nil, that
6
+ # value has no bound.
7
+ def get_int(str, cmd, min=nil, max=nil, default=1)
8
+ return default unless str
9
+ begin
10
+ int = Integer(str)
11
+ if min and int < min
12
+ print_error "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
13
+ return nil
14
+ elsif max and int > max
15
+ print_error "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
16
+ return nil
17
+ end
18
+ return int
19
+ rescue
20
+ print_error "%s argument '%s' needs to be a number.\n" % [cmd, str]
21
+ return nil
22
+ end
23
+ end
24
+
25
+ # Return true if code is syntactically correct for Ruby.
26
+ def syntax_valid?(code)
27
+ eval("BEGIN {return true}\n#{code}", nil, "", 0)
28
+ rescue Exception
29
+ false
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,155 @@
1
+ require 'ruby-debug-ide/interface'
2
+ require 'ruby-debug-ide/command'
3
+
4
+ module Debugger
5
+ class IdeCommandProcessor
6
+ def initialize(interface = nil)
7
+ @interface = interface
8
+ @printer = XmlPrinter.new(@interface)
9
+ end
10
+
11
+ def print(*args)
12
+ @interface.print(*args)
13
+ end
14
+
15
+ def process_commands
16
+ unless Debugger.handler.at_line?
17
+ @printer.print_error "There is no thread suspended at the time and therefore no context to execute '#{input.gsub('%', '%%')}'"
18
+ return
19
+ end
20
+ context = Debugger.handler.context
21
+ file = Debugger.handler.file
22
+ line = Debugger.handler.line
23
+ state = State.new do |s|
24
+ s.context = context
25
+ s.file = file
26
+ s.line = line
27
+ s.binding = context.frame_binding(0)
28
+ s.interface = @interface
29
+ end
30
+ event_cmds = Command.commands.map{|cmd| cmd.new(state, @printer) }
31
+ until state.proceed? do
32
+ input = @interface.command_queue.pop
33
+ catch(:debug_error) do
34
+ splitter[input].each do |input|
35
+ # escape % since print_debug might use printf
36
+ @printer.print_debug "Processing in context: #{input.gsub('%', '%%')}"
37
+ if (cmd = event_cmds.find { |c| c.match(input) })
38
+ if context.dead? && cmd.class.need_context
39
+ @printer.print_msg "Command is unavailable\n"
40
+ else
41
+ cmd.execute
42
+ end
43
+ else
44
+ @printer.print_msg "Unknown command: #{input}"
45
+ end
46
+ end
47
+ end
48
+ state.restore_context
49
+ end
50
+ rescue ::Exception
51
+ @printer.print_error "INTERNAL ERROR!!! #{$!}\n" rescue nil
52
+ @printer.print_error $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
53
+ end
54
+
55
+ def splitter
56
+ lambda do |str|
57
+ str.split(/;/).inject([]) do |m, v|
58
+ if m.empty?
59
+ m << v
60
+ else
61
+ if m.last[-1] == ?\\
62
+ m.last[-1,1] = ''
63
+ m.last << ';' << v
64
+ else
65
+ m << v
66
+ end
67
+ end
68
+ m
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ class IdeControlCommandProcessor < IdeCommandProcessor# :nodoc:
75
+ def process_commands
76
+ @printer.print_debug("Starting control thread")
77
+ ctrl_cmd_classes = Command.commands.select{|cmd| cmd.control}
78
+ state = ControlState.new(@interface)
79
+ ctrl_cmds = ctrl_cmd_classes.map{|cmd| cmd.new(state, @printer)}
80
+ while input = @interface.read_command
81
+ # escape % since print_debug might use printf
82
+ # sleep 0.3
83
+ catch(:debug_error) do
84
+ if cmd = ctrl_cmds.find{|c| c.match(input) }
85
+ @printer.print_debug "Processing in control: #{input.gsub('%', '%%')}"
86
+ cmd.execute
87
+ else
88
+ @interface.command_queue << input
89
+ end
90
+ end
91
+ end
92
+ rescue ::Exception
93
+ @printer.print_debug "INTERNAL ERROR!!! #{$!}\n" rescue nil
94
+ @printer.print_error "INTERNAL ERROR!!! #{$!}\n" rescue nil
95
+ @printer.print_error $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
96
+ ensure
97
+ @interface.close
98
+ end
99
+ end
100
+
101
+ class State # :nodoc:
102
+
103
+ attr_accessor :context, :original_context
104
+ attr_accessor :file, :line, :binding
105
+ attr_accessor :frame_pos, :previous_line
106
+ attr_accessor :interface
107
+
108
+ def initialize
109
+ @frame_pos = 0
110
+ @previous_line = nil
111
+ @proceed = false
112
+ yield self
113
+ @original_context = context
114
+ end
115
+
116
+ def print(*args)
117
+ @interface.print(*args)
118
+ end
119
+
120
+ def proceed?
121
+ @proceed
122
+ end
123
+
124
+ def proceed
125
+ @proceed = true
126
+ end
127
+
128
+ def restore_context
129
+ @context = @original_context
130
+ end
131
+ end
132
+
133
+ class ControlState # :nodoc:
134
+
135
+ def initialize(interface)
136
+ @interface = interface
137
+ end
138
+
139
+ def proceed
140
+ end
141
+
142
+ def print(*args)
143
+ @interface.print(*args)
144
+ end
145
+
146
+ def context
147
+ nil
148
+ end
149
+
150
+ def file
151
+ print "ERROR: No filename given.\n"
152
+ throw :debug_error
153
+ end
154
+ end
155
+ end