ruby-debug193 0.0.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 (40) hide show
  1. data/AUTHORS +10 -0
  2. data/LICENSE +23 -0
  3. data/bin/rdebug +398 -0
  4. data/cli/ruby-debug.rb +173 -0
  5. data/cli/ruby-debug/command.rb +228 -0
  6. data/cli/ruby-debug/commands/breakpoints.rb +153 -0
  7. data/cli/ruby-debug/commands/catchpoint.rb +55 -0
  8. data/cli/ruby-debug/commands/condition.rb +49 -0
  9. data/cli/ruby-debug/commands/continue.rb +38 -0
  10. data/cli/ruby-debug/commands/control.rb +107 -0
  11. data/cli/ruby-debug/commands/display.rb +120 -0
  12. data/cli/ruby-debug/commands/edit.rb +48 -0
  13. data/cli/ruby-debug/commands/enable.rb +202 -0
  14. data/cli/ruby-debug/commands/eval.rb +176 -0
  15. data/cli/ruby-debug/commands/finish.rb +42 -0
  16. data/cli/ruby-debug/commands/frame.rb +301 -0
  17. data/cli/ruby-debug/commands/help.rb +56 -0
  18. data/cli/ruby-debug/commands/info.rb +469 -0
  19. data/cli/ruby-debug/commands/irb.rb +123 -0
  20. data/cli/ruby-debug/commands/jump.rb +66 -0
  21. data/cli/ruby-debug/commands/kill.rb +51 -0
  22. data/cli/ruby-debug/commands/list.rb +94 -0
  23. data/cli/ruby-debug/commands/method.rb +84 -0
  24. data/cli/ruby-debug/commands/quit.rb +39 -0
  25. data/cli/ruby-debug/commands/reload.rb +40 -0
  26. data/cli/ruby-debug/commands/save.rb +90 -0
  27. data/cli/ruby-debug/commands/set.rb +237 -0
  28. data/cli/ruby-debug/commands/show.rb +253 -0
  29. data/cli/ruby-debug/commands/source.rb +36 -0
  30. data/cli/ruby-debug/commands/stepping.rb +81 -0
  31. data/cli/ruby-debug/commands/threads.rb +189 -0
  32. data/cli/ruby-debug/commands/tmate.rb +36 -0
  33. data/cli/ruby-debug/commands/trace.rb +57 -0
  34. data/cli/ruby-debug/commands/variables.rb +199 -0
  35. data/cli/ruby-debug/debugger.rb +5 -0
  36. data/cli/ruby-debug/helper.rb +69 -0
  37. data/cli/ruby-debug/interface.rb +232 -0
  38. data/cli/ruby-debug/processor.rb +474 -0
  39. data/rdbg.rb +33 -0
  40. metadata +144 -0
@@ -0,0 +1,38 @@
1
+ module Debugger
2
+
3
+ # Implements debugger "continue" command.
4
+ class ContinueCommand < Command
5
+ self.allow_in_post_mortem = true
6
+ self.need_context = false
7
+ def regexp
8
+ /^\s* c(?:ont(?:inue)?)? (?:\s+(.*))? $/x
9
+ end
10
+
11
+ def execute
12
+ if @match[1] && !@state.context.dead?
13
+ filename = File.expand_path(@state.file)
14
+ line_number = get_int(@match[1], "Continue", 0, nil, 0)
15
+ return unless line_number
16
+ unless LineCache.trace_line_numbers(filename).member?(line_number)
17
+ errmsg("Line %d is not a stopping point in file \"%s\".\n",
18
+ line_number, filename)
19
+ return
20
+ end
21
+ @state.context.set_breakpoint(filename, line_number)
22
+ end
23
+ @state.proceed
24
+ end
25
+
26
+ class << self
27
+ def help_command
28
+ 'continue'
29
+ end
30
+
31
+ def help(cmd)
32
+ %{
33
+ c[ont[inue]][ nnn]\trun until program ends, hits a breakpoint or reaches line nnn
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,107 @@
1
+ module Debugger
2
+ class RestartCommand < Command # :nodoc:
3
+ self.allow_in_control = true
4
+
5
+ def regexp
6
+ / ^\s*
7
+ (?:restart|R)
8
+ (?:\s+ (\S?.*\S))? \s*
9
+ $
10
+ /ix
11
+ end
12
+
13
+ def execute
14
+ if not defined? Debugger::PROG_SCRIPT
15
+ errmsg "Don't know name of debugged program\n"
16
+ return
17
+ end
18
+ prog_script = Debugger::PROG_SCRIPT
19
+ if not defined? Debugger::RDEBUG_SCRIPT
20
+ # FIXME? Should ask for confirmation?
21
+ print "Debugger was not called from the outset...\n"
22
+ rdebug_script = prog_script
23
+ else
24
+ rdebug_script = Debugger::RDEBUG_SCRIPT
25
+ end
26
+ begin
27
+ Dir.chdir(Debugger::INITIAL_DIR)
28
+ rescue
29
+ print "Failed to change initial directory #{Debugger::INITIAL_DIR}"
30
+ end
31
+ if not File.exist?(File.expand_path(prog_script))
32
+ errmsg "Ruby program #{prog_script} doesn't exist\n"
33
+ return
34
+ end
35
+ if not File.executable?(prog_script) and rdebug_script == prog_script
36
+ print "Ruby program #{prog_script} doesn't seem to be executable...\n"
37
+ print "We'll add a call to Ruby.\n"
38
+ ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end
39
+ rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}"
40
+ else
41
+ rdebug_script += ' '
42
+ end
43
+ if @match[1]
44
+ argv = [prog_script] + @match[1].split(/[ \t]+/)
45
+ else
46
+ if not defined? Command.settings[:argv]
47
+ errmsg "Arguments have not been set. Use 'set args' to set them.\n"
48
+ return
49
+ else
50
+ argv = Command.settings[:argv]
51
+ end
52
+ end
53
+ args = argv.join(' ')
54
+
55
+ # An execv would be preferable to the "exec" below.
56
+ cmd = rdebug_script + args
57
+ print "Re exec'ing:\n\t#{cmd}\n"
58
+ exec cmd
59
+ rescue Errno::EOPNOTSUPP
60
+ print "Restart command is not available at this time.\n"
61
+ end
62
+
63
+ class << self
64
+ def help_command
65
+ 'restart'
66
+ end
67
+
68
+ def help(cmd)
69
+ %{
70
+ restart|R [args]
71
+ Restart the program. This is is a re-exec - all debugger state
72
+ is lost. If command arguments are passed those are used.
73
+ }
74
+ end
75
+ end
76
+ end
77
+
78
+ class InterruptCommand < Command # :nodoc:
79
+ self.allow_in_control = true
80
+ self.allow_in_post_mortem = false
81
+ self.event = false
82
+ self.need_context = true
83
+
84
+ def regexp
85
+ /^\s*i(?:nterrupt)?\s*$/
86
+ end
87
+
88
+ def execute
89
+ unless Debugger.interrupt_last
90
+ context = Debugger.thread_context(Thread.main)
91
+ context.interrupt
92
+ end
93
+ end
94
+
95
+ class << self
96
+ def help_command
97
+ 'interrupt'
98
+ end
99
+
100
+ def help(cmd)
101
+ %{
102
+ i[nterrupt]\tinterrupt the program
103
+ }
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,120 @@
1
+ module Debugger
2
+ module DisplayFunctions # :nodoc:
3
+ def display_expression(exp)
4
+ print "%s = %s\n", exp, debug_silent_eval(exp).to_s
5
+ end
6
+
7
+ def active_display_expressions?
8
+ @state.display.select{|d| d[0]}.size > 0
9
+ end
10
+
11
+ def print_display_expressions
12
+ n = 1
13
+ for d in @state.display
14
+ if d[0]
15
+ print "%d: ", n
16
+ display_expression(d[1])
17
+ end
18
+ n += 1
19
+ end
20
+ end
21
+ end
22
+
23
+ class AddDisplayCommand < Command # :nodoc:
24
+ def regexp
25
+ /^\s*disp(?:lay)?\s+(.+)$/
26
+ end
27
+
28
+ def execute
29
+ exp = @match[1]
30
+ @state.display.push [true, exp]
31
+ print "%d: ", @state.display.size
32
+ display_expression(exp)
33
+ end
34
+
35
+ class << self
36
+ def help_command
37
+ 'display'
38
+ end
39
+
40
+ def help(cmd)
41
+ %{
42
+ disp[lay] <expression>\tadd expression into display expression list
43
+ }
44
+ end
45
+ end
46
+ end
47
+
48
+ class DisplayCommand < Command # :nodoc:
49
+ def self.always_run
50
+ Debugger.annotate = 0 unless Debugger.annotate
51
+ if Debugger.annotate > 1
52
+ 0
53
+ else
54
+ 2
55
+ end
56
+ end
57
+
58
+ def regexp
59
+ /^\s*disp(?:lay)?$/
60
+ end
61
+
62
+ def execute
63
+ print_display_expressions
64
+ end
65
+
66
+ class << self
67
+ def help_command
68
+ 'display'
69
+ end
70
+
71
+ def help(cmd)
72
+ %{
73
+ disp[lay]\t\tdisplay expression list
74
+ }
75
+ end
76
+ end
77
+ end
78
+
79
+ class DeleteDisplayCommand < Command # :nodoc:
80
+
81
+ def regexp
82
+ /^\s* undisp(?:lay)? \s* (?:(\S+))?$/x
83
+ end
84
+
85
+ def execute
86
+ unless pos = @match[1]
87
+ if confirm("Clear all expressions? (y/n) ")
88
+ for d in @state.display
89
+ d[0] = false
90
+ end
91
+ end
92
+ else
93
+ pos = get_int(pos, "Undisplay")
94
+ return unless pos
95
+ if @state.display[pos-1]
96
+ @state.display[pos-1][0] = nil
97
+ else
98
+ errmsg "Display expression %d is not defined.\n", pos
99
+ end
100
+ end
101
+ end
102
+
103
+ class << self
104
+ def help_command
105
+ 'undisplay'
106
+ end
107
+
108
+ def help(cmd)
109
+ %{
110
+ undisp[lay][ nnn]
111
+ Cancel some expressions to be displayed when program stops.
112
+ Arguments are the code numbers of the expressions to stop displaying.
113
+ No argument means cancel all automatic-display expressions.
114
+ "delete display" has the same effect as this command.
115
+ Do "info display" to see current list of code numbers.
116
+ }
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,48 @@
1
+ module Debugger
2
+ class Edit < Command # :nodoc:
3
+ self.allow_in_control = true
4
+ def regexp
5
+ /^\s* ed(?:it)? (?:\s+(.*))?$/ix
6
+ end
7
+
8
+ def execute
9
+ if not @match[1] or @match[1].strip.empty?
10
+ unless @state.context
11
+ errmsg "We are not in a state that has an associated file.\n"
12
+ return
13
+ end
14
+ file = @state.file
15
+ line_number = @state.line
16
+ elsif @pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1])
17
+ file, line_number = @pos_match.captures
18
+ else
19
+ errmsg "Invalid file/line number specification: #{@match[1]}\n"
20
+ return
21
+ end
22
+ editor = ENV['EDITOR'] || 'ex'
23
+ if File.readable?(file)
24
+ system("#{editor} +#{line_number} #{file}")
25
+ else
26
+ errmsg "File \"#{file}\" is not readable.\n"
27
+ end
28
+ end
29
+
30
+ class << self
31
+ def help_command
32
+ 'edit'
33
+ end
34
+
35
+ def help(cmd)
36
+ %{
37
+ Edit specified file.
38
+
39
+ With no argument, edits file containing most recent line listed.
40
+ Editing targets can also be specified in this:
41
+ FILE:LINENUM, to edit at that line in that file,
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ end # module Debugger
@@ -0,0 +1,202 @@
1
+ module Debugger
2
+ # Mix-in module to assist in command parsing.
3
+ module EnableDisableFunctions # :nodoc:
4
+ def enable_disable_breakpoints(is_enable, args)
5
+ breakpoints = Debugger.breakpoints.sort_by{|b| b.id }
6
+ largest = breakpoints.inject(0) do |largest, b|
7
+ largest = b.id if b.id > largest
8
+ end
9
+ if 0 == largest
10
+ errmsg "No breakpoints have been set.\n"
11
+ return
12
+ end
13
+ args.each do |pos|
14
+ pos = get_int(pos, "#{is_enable} breakpoints", 1, largest)
15
+ return nil unless pos
16
+ breakpoints.each do |b|
17
+ if b.id == pos
18
+ enabled = ("Enable" == is_enable)
19
+ if enabled
20
+ unless syntax_valid?(b.expr)
21
+ errmsg("Expression \"#{b.expr}\" syntactically incorrect; breakpoint remains disabled.\n")
22
+ break
23
+ end
24
+ end
25
+ b.enabled = ("Enable" == is_enable)
26
+ break
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def enable_disable_display(is_enable, args)
33
+ if 0 == @state.display.size
34
+ errmsg "No display expressions have been set.\n"
35
+ return
36
+ end
37
+ args.each do |pos|
38
+ pos = get_int(pos, "#{is_enable} display", 1, @state.display.size)
39
+ return nil unless pos
40
+ @state.display[pos-1][0] = ("Enable" == is_enable)
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ class EnableCommand < Command # :nodoc:
47
+ Subcommands =
48
+ [
49
+ ['breakpoints', 2, "Enable specified breakpoints",
50
+ "Give breakpoint numbers (separated by spaces) as arguments.
51
+ This is used to cancel the effect of the \"disable\" command."
52
+ ],
53
+ ['display', 2,
54
+ "Enable some expressions to be displayed when program stops",
55
+ "Arguments are the code numbers of the expressions to resume displaying.
56
+ Do \"info display\" to see current list of code numbers."],
57
+ ].map do |name, min, short_help, long_help|
58
+ SubcmdStruct.new(name, min, short_help, long_help)
59
+ end unless defined?(Subcommands)
60
+
61
+ def regexp
62
+ /^\s* en(?:able)? (?:\s+(.*))?$/ix
63
+ end
64
+
65
+ def execute
66
+ if not @match[1]
67
+ errmsg "\"enable\" must be followed \"display\", \"breakpoints\"" +
68
+ " or breakpoint numbers.\n"
69
+ else
70
+ args = @match[1].split(/[ \t]+/)
71
+ param = args.shift
72
+ subcmd = find(Subcommands, param)
73
+ if subcmd
74
+ send("enable_#{subcmd.name}", args)
75
+ else
76
+ send("enable_breakpoints", args.unshift(param))
77
+ end
78
+ end
79
+ end
80
+
81
+ def enable_breakpoints(args)
82
+ enable_disable_breakpoints("Enable", args)
83
+ end
84
+
85
+ def enable_display(args)
86
+ enable_disable_display("Enable", args)
87
+ end
88
+
89
+ class << self
90
+ def help_command
91
+ 'enable'
92
+ end
93
+
94
+ def help(args)
95
+ if args[1]
96
+ s = args[1]
97
+ subcmd = Subcommands.find do |try_subcmd|
98
+ (s.size >= try_subcmd.min) and
99
+ (try_subcmd.name[0..s.size-1] == s)
100
+ end
101
+ if subcmd
102
+ str = subcmd.short_help + '.'
103
+ str += "\n" + subcmd.long_help if subcmd.long_help
104
+ return str
105
+ else
106
+ return "Invalid 'enable' subcommand '#{args[1]}'."
107
+ end
108
+ end
109
+ s = %{
110
+ Enable some things.
111
+ This is used to cancel the effect of the "disable" command.
112
+ --
113
+ List of enable subcommands:
114
+ --
115
+ }
116
+ for subcmd in Subcommands do
117
+ s += "enable #{subcmd.name} -- #{subcmd.short_help}\n"
118
+ end
119
+ return s
120
+ end
121
+ end
122
+ end
123
+
124
+ class DisableCommand < Command # :nodoc:
125
+ Subcommands =
126
+ [
127
+ ['breakpoints', 1, "Disable some breakpoints",
128
+ "Arguments are breakpoint numbers with spaces in between.
129
+ A disabled breakpoint is not forgotten, but has no effect until reenabled."],
130
+ ['display', 1, "Disable some display expressions when program stops",
131
+ "Arguments are the code numbers of the expressions to stop displaying.
132
+ Do \"info display\" to see current list of code numbers."],
133
+ ].map do |name, min, short_help, long_help|
134
+ SubcmdStruct.new(name, min, short_help, long_help)
135
+ end unless defined?(Subcommands)
136
+
137
+ def regexp
138
+ /^\s* dis(?:able)? (?:\s+(.*))?$/ix
139
+ end
140
+
141
+ def execute
142
+ if not @match[1]
143
+ errmsg "\"disable\" must be followed \"display\", \"breakpoints\"" +
144
+ " or breakpoint numbers.\n"
145
+ else
146
+ args = @match[1].split(/[ \t]+/)
147
+ param = args.shift
148
+ subcmd = find(Subcommands, param)
149
+ if subcmd
150
+ send("disable_#{subcmd.name}", args)
151
+ else
152
+ send("disable_breakpoints", args.unshift(param))
153
+ end
154
+ end
155
+ end
156
+
157
+ def disable_breakpoints(args)
158
+ enable_disable_breakpoints("Disable", args)
159
+ end
160
+
161
+ def disable_display(args)
162
+ enable_disable_display("Disable", args)
163
+ end
164
+
165
+ class << self
166
+ def help_command
167
+ 'disable'
168
+ end
169
+
170
+ def help(args)
171
+ if args[1]
172
+ s = args[1]
173
+ subcmd = Subcommands.find do |try_subcmd|
174
+ (s.size >= try_subcmd.min) and
175
+ (try_subcmd.name[0..s.size-1] == s)
176
+ end
177
+ if subcmd
178
+ str = subcmd.short_help + '.'
179
+ str += "\n" + subcmd.long_help if subcmd.long_help
180
+ return str
181
+ else
182
+ return "Invalid 'disable' subcommand '#{args[1]}'."
183
+ end
184
+ end
185
+ s = %{
186
+ Disable some things.
187
+
188
+ A disabled item is not forgotten, but has no effect until reenabled.
189
+ Use the "enable" command to have it take effect again.
190
+ --
191
+ List of disable subcommands:
192
+ --
193
+ }
194
+ for subcmd in Subcommands do
195
+ s += "disable #{subcmd.name} -- #{subcmd.short_help}\n"
196
+ end
197
+ return s
198
+ end
199
+ end
200
+ end
201
+
202
+ end # module Debugger