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,177 @@
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/helper'
8
+ require 'delegate'
9
+
10
+ module Debugger
11
+
12
+ class Command < SimpleDelegator # :nodoc:
13
+ SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
14
+ defined?(SubcmdStruct)
15
+
16
+ # Find param in subcmds. param id downcased and can be abbreviated
17
+ # to the minimum length listed in the subcommands
18
+ def find(subcmds, param)
19
+ param.downcase!
20
+ for try_subcmd in subcmds do
21
+ if (param.size >= try_subcmd.min) and
22
+ (try_subcmd.name[0..param.size-1] == param)
23
+ return try_subcmd
24
+ end
25
+ end
26
+ return nil
27
+ end
28
+
29
+ class << self
30
+ def commands
31
+ @commands ||= []
32
+ end
33
+
34
+ DEF_OPTIONS = {
35
+ :event => true,
36
+ :control => false,
37
+ :unknown => false,
38
+ :need_context => false,
39
+ }
40
+
41
+ def inherited(klass)
42
+ DEF_OPTIONS.each do |o, v|
43
+ klass.options[o] = v if klass.options[o].nil?
44
+ end
45
+ commands << klass
46
+ end
47
+
48
+ def load_commands
49
+ dir = File.dirname(__FILE__)
50
+ Dir[File.join(dir, 'commands', '*')].each do |file|
51
+ require file if file =~ /\.rb$/
52
+ end
53
+ Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
54
+ include mod
55
+ end
56
+ end
57
+
58
+ def method_missing(meth, *args, &block)
59
+ if meth.to_s =~ /^(.+?)=$/
60
+ @options[$1.intern] = args.first
61
+ else
62
+ if @options.has_key?(meth)
63
+ @options[meth]
64
+ else
65
+ super
66
+ end
67
+ end
68
+ end
69
+
70
+ def options
71
+ @options ||= {}
72
+ end
73
+
74
+ def unescape_incoming(str)
75
+ str.gsub(/((?:^|[^\\])(?:\\\\)*)((?:\\n)+)/) do |_|
76
+ $1 + "\n" * ($2.size / 2)
77
+ end.gsub(/\\\\/, '\\')
78
+ end
79
+
80
+ def file_filter_supported?
81
+ defined?(Debugger.file_filter)
82
+ end
83
+ end
84
+
85
+ def initialize(state, printer)
86
+ @state, @printer = state, printer
87
+ super @printer
88
+ end
89
+
90
+ def match(input)
91
+ @match = regexp.match(input)
92
+ end
93
+
94
+ protected
95
+
96
+ def errmsg(*args)
97
+ @printer.print_error(*args)
98
+ end
99
+
100
+ def print(*args)
101
+ @state.print(*args)
102
+ end
103
+
104
+ # see Timeout::timeout, the difference is that we must use a DebugThread
105
+ # because every other thread would be halted when the event hook is reached
106
+ # in ruby-debug.c
107
+ def timeout(sec)
108
+ return yield if sec == nil or sec.zero?
109
+ if Thread.respond_to?(:critical) and Thread.critical
110
+ raise ThreadError, "timeout within critical session"
111
+ end
112
+ begin
113
+ x = Thread.current
114
+ y = DebugThread.start {
115
+ sleep sec
116
+ x.raise StandardError, "Timeout: evaluation took longer than #{sec} seconds." if x.alive?
117
+ }
118
+ yield sec
119
+ ensure
120
+ y.kill if y and y.alive?
121
+ end
122
+ end
123
+
124
+ def debug_eval(str, b = get_binding)
125
+ begin
126
+ str = str.to_s
127
+ str.force_encoding('UTF-8') if(RUBY_VERSION >= '2.0')
128
+ to_inspect = Command.unescape_incoming(str)
129
+ max_time = Debugger.evaluation_timeout
130
+ @printer.print_debug("Evaluating %s with timeout after %i sec", str, max_time)
131
+ timeout(max_time) do
132
+ eval(to_inspect, b)
133
+ end
134
+ rescue StandardError, ScriptError => e
135
+ @printer.print_exception(e, @state.binding)
136
+ throw :debug_error
137
+ end
138
+ end
139
+
140
+ def debug_silent_eval(str)
141
+ begin
142
+ str = str.to_s
143
+ eval(str, get_binding)
144
+ rescue StandardError, ScriptError
145
+ nil
146
+ end
147
+ end
148
+
149
+ def get_binding
150
+ @state.context.frame_binding(@state.frame_pos)
151
+ end
152
+
153
+ def line_at(file, line)
154
+ Debugger.line_at(file, line)
155
+ end
156
+
157
+ def get_context(thnum)
158
+ Debugger.contexts.find{|c| c.thnum == thnum}
159
+ end
160
+
161
+ def realpath(filename)
162
+ is_dir = filename.end_with?(File::SEPARATOR)
163
+ if filename.index(File::SEPARATOR) || File::ALT_SEPARATOR && filename.index(File::ALT_SEPARATOR)
164
+ filename = File.expand_path(filename)
165
+ end
166
+ if (RUBY_VERSION < '1.9') || (RbConfig::CONFIG['host_os'] =~ /mswin/)
167
+ filename
168
+ else
169
+ filename = File.realpath(filename) rescue filename
170
+ filename = filename + File::SEPARATOR if is_dir && !filename.end_with?(File::SEPARATOR)
171
+ filename
172
+ end
173
+ end
174
+ end
175
+
176
+ Command.load_commands
177
+ end
@@ -0,0 +1,128 @@
1
+ module Debugger
2
+ class AddBreakpoint < Command # :nodoc:
3
+ self.control = true
4
+
5
+ def regexp
6
+ / ^\s*
7
+ b(?:reak)?
8
+ (?: \s+
9
+ (?:
10
+ (\d+) |
11
+ (.+?)[:.#]([^.:\s]+)
12
+ ))?
13
+ (?:\s+
14
+ if\s+(.+)
15
+ )?
16
+ $
17
+ /x
18
+ end
19
+
20
+ def execute
21
+ if @match[1]
22
+ line, _, _, expr = @match.captures
23
+ else
24
+ _, file, line, expr = @match.captures
25
+ end
26
+
27
+ if file.nil?
28
+ file = File.basename(@state.file)
29
+ else
30
+ if line !~ /^\d+$/
31
+ klass = debug_silent_eval(file)
32
+ if klass && !klass.kind_of?(Module)
33
+ print_error "Unknown class #{file}"
34
+ throw :debug_error
35
+ end
36
+ file = klass.name if klass
37
+ else
38
+ file = realpath(file)
39
+ end
40
+ end
41
+
42
+ if line =~ /^\d+$/
43
+ line = line.to_i
44
+ else
45
+ line = line.intern.id2name
46
+ end
47
+
48
+ b = Debugger.add_breakpoint file, line, expr
49
+ print_breakpoint_added b
50
+ end
51
+
52
+ class << self
53
+ def help_command
54
+ 'break'
55
+ end
56
+
57
+ def help(cmd)
58
+ %{
59
+ b[reak] file:line [if expr]
60
+ b[reak] [file|class(:|.|#)]<line|method> [if expr] -
61
+ \tset breakpoint to some position, (optionally) if expr == true
62
+ }
63
+ end
64
+ end
65
+ end
66
+
67
+ class BreakpointsCommand < Command # :nodoc:
68
+ self.control = true
69
+
70
+ def regexp
71
+ /^\s*info\s*break$/
72
+ end
73
+
74
+ def execute
75
+ print_breakpoints Debugger.breakpoints
76
+ end
77
+
78
+ class << self
79
+ def help_command
80
+ 'break'
81
+ end
82
+
83
+ def help(cmd)
84
+ %{
85
+ b[reak]\tlist breakpoints
86
+ }
87
+ end
88
+ end
89
+ end
90
+
91
+ class DeleteBreakpointCommand < Command # :nodoc:
92
+ self.control = true
93
+
94
+ def regexp
95
+ /^\s*del(?:ete)?(?:\s+(.*))?$/
96
+ end
97
+
98
+ def execute
99
+ brkpts = @match[1]
100
+ unless brkpts
101
+ Debugger.breakpoints.clear
102
+ else
103
+ brkpts.split(/[ \t]+/).each do |pos|
104
+ pos = get_int(pos, "Delete", 1)
105
+ return unless pos
106
+ b = Debugger.remove_breakpoint(pos)
107
+ if b
108
+ print_breakpoint_deleted b
109
+ else
110
+ print_error "No breakpoint number %d\n", pos
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ class << self
117
+ def help_command
118
+ 'delete'
119
+ end
120
+
121
+ def help(cmd)
122
+ %{
123
+ del[ete][ nnn...]\tdelete some or all breakpoints
124
+ }
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,64 @@
1
+ module Debugger
2
+ class CatchCommand < Command # :nodoc:
3
+ self.control = true
4
+
5
+ def regexp
6
+ /^\s* cat(?:ch)?
7
+ (?:\s+ (\S+))?
8
+ (?:\s+ (off))? \s* $/ix
9
+ end
10
+
11
+ def execute
12
+ excn = @match[1]
13
+ if not excn
14
+ # No args given.
15
+ errmsg "Exception class must be specified for 'catch' command"
16
+ elsif not @match[2]
17
+ # One arg given.
18
+ if 'off' == excn
19
+ clear_catchpoints
20
+ else
21
+ Debugger.add_catchpoint(excn)
22
+ print_catchpoint_set(excn)
23
+ end
24
+ elsif @match[2] != 'off'
25
+ errmsg "Off expected. Got %s\n", @match[2]
26
+ elsif remove_catchpoint(excn)
27
+ print_catchpoint_deleted(excn)
28
+ else
29
+ errmsg "Catch for exception %s not found.\n", excn
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def help_command
35
+ 'catch'
36
+ end
37
+
38
+ def help(cmd)
39
+ %{
40
+ cat[ch]\t\t\tshow catchpoint
41
+ cat[ch] off \tremove all catch points
42
+ cat[ch] <an Exception>\tset catchpoint to an exception
43
+ cat[ch] <an Exception> off \tremove catchpoint for an exception
44
+ }
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def clear_catchpoints
51
+ if Debugger.respond_to?(:clear_catchpoints)
52
+ Debugger.clear_catchpoints
53
+ else
54
+ Debugger.catchpoints.clear
55
+ end
56
+ end
57
+
58
+ def remove_catchpoint(excn)
59
+ return Debugger.remove_catchpoint(excn) if Debugger.respond_to?(:remove_catchpoint)
60
+ return Debugger.catchpoints.delete(excn) if Debugger.catchpoints.member?(excn)
61
+ false
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,51 @@
1
+ module Debugger
2
+
3
+ class ConditionCommand < Command # :nodoc:
4
+ self.control = true
5
+
6
+ def regexp
7
+ /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix
8
+ end
9
+
10
+ def execute
11
+ if not @match[1]
12
+ errmsg "\"condition\" must be followed a breakpoint number and expression\n"
13
+ else
14
+ breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
15
+ largest = breakpoints.inject(0) do |largest_so_far, b|
16
+ b.id if b.id > largest_so_far
17
+ end
18
+ if 0 == largest
19
+ print "No breakpoints have been set.\n"
20
+ return
21
+ end
22
+ pos = get_int(@match[1], "Condition", 1, largest)
23
+ return unless pos
24
+ breakpoints.each do |b|
25
+ if b.id == pos
26
+ b.expr = @match[2].empty? ? nil : @match[2]
27
+ print_contdition_set(b.id)
28
+ break
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def help_command
37
+ 'condition'
38
+ end
39
+
40
+ def help(cmd)
41
+ %{
42
+ Condition breakpoint-number expression
43
+ Specify breakpoint number N to break only if COND is true.
44
+ N is an integer and COND is an expression to be evaluated whenever
45
+ breakpoint N is reached. If the empty string is used, the condition is removed.
46
+ }
47
+ end
48
+ end
49
+ end
50
+
51
+ end # module Debugger
@@ -0,0 +1,158 @@
1
+ module Debugger
2
+ class QuitCommand < Command # :nodoc:
3
+ self.control = true
4
+
5
+ def regexp
6
+ /^\s*(?:q(?:uit)?|exit)\s*$/
7
+ end
8
+
9
+ def execute
10
+ begin
11
+ @printer.print_msg("finished")
12
+ @printer.print_debug("Exiting debugger.")
13
+ ensure
14
+ exit! # exit -> exit!: No graceful way to stop threads...
15
+ end
16
+ end
17
+
18
+ class << self
19
+ def help_command
20
+ %w[quit exit]
21
+ end
22
+
23
+ def help(cmd)
24
+ %{
25
+ q[uit]\texit from debugger,
26
+ exit\talias to quit
27
+ }
28
+ end
29
+ end
30
+ end
31
+
32
+ class RestartCommand < Command # :nodoc:
33
+ self.control = true
34
+
35
+ def regexp
36
+ / ^\s*
37
+ (restart|R)
38
+ (\s+ \S+ .*)?
39
+ $
40
+ /x
41
+ end
42
+
43
+ def execute
44
+ if not defined? Debugger::RDEBUG_SCRIPT or not defined? Debugger::ARGV
45
+ print "We are not in a context we can restart from.\n"
46
+ return
47
+ end
48
+ if @match[2]
49
+ args = Debugger::PROG_SCRIPT + " " + @match[2]
50
+ else
51
+ args = Debugger::ARGV.join(" ")
52
+ end
53
+
54
+ # An execv would be preferable to the "exec" below.
55
+ cmd = Debugger::RDEBUG_SCRIPT + " " + args
56
+ print "Re exec'ing:\n\t#{cmd}\n"
57
+ exec cmd
58
+ end
59
+
60
+ class << self
61
+ def help_command
62
+ 'restart'
63
+ end
64
+
65
+ def help(cmd)
66
+ %{
67
+ restart|R [args]
68
+ Restart the program. This is is a re-exec - all debugger state
69
+ is lost. If command arguments are passed those are used.
70
+ }
71
+ end
72
+ end
73
+ end
74
+
75
+ class StartCommand < Command # :nodoc:
76
+ self.control = true
77
+
78
+ def regexp
79
+ /^\s*(start)(\s+ \S+ .*)?$/x
80
+ end
81
+
82
+ def execute
83
+ @printer.print_debug("Starting: running program script")
84
+ Debugger.run_prog_script #Debugger.prog_script_running?
85
+ end
86
+
87
+ class << self
88
+ def help_command
89
+ 'start'
90
+ end
91
+
92
+ def help(cmd)
93
+ %{
94
+ run prog script
95
+ }
96
+ end
97
+ end
98
+ end
99
+
100
+
101
+ class InterruptCommand < Command # :nodoc:
102
+ self.event = false
103
+ self.control = true
104
+ self.need_context = true
105
+
106
+ def regexp
107
+ /^\s*i(?:nterrupt)?\s*$/
108
+ end
109
+
110
+ def execute
111
+ unless Debugger.interrupt_last
112
+ context = Debugger.thread_context(Thread.main)
113
+ context.interrupt
114
+ end
115
+ end
116
+
117
+ class << self
118
+ def help_command
119
+ 'interrupt'
120
+ end
121
+
122
+ def help(cmd)
123
+ %{
124
+ i[nterrupt]\tinterrupt the program
125
+ }
126
+ end
127
+ end
128
+ end
129
+
130
+
131
+ class DetachCommand < Command # :nodoc:
132
+ self.control = true
133
+
134
+ def regexp
135
+ /^\s*detach\s*$/
136
+ end
137
+
138
+ def execute
139
+ Debugger.stop
140
+ Debugger.interface.close
141
+ Debugger::MultiProcess.undo_monkey
142
+ Debugger.control_thread = nil
143
+ Thread.current.exit #@control_thread is a current thread
144
+ end
145
+
146
+ class << self
147
+ def help_command
148
+ 'detach'
149
+ end
150
+
151
+ def help(cmd)
152
+ %{
153
+ detach\ndetach debugger\nnote: this option is only for remote debugging (or local attach)
154
+ }
155
+ end
156
+ end
157
+ end
158
+ end