ruby-debug-ide-docker 0.6.1

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 (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