ruby-debug19 0.11.5
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.
- data/AUTHORS +9 -0
- data/LICENSE +23 -0
- data/bin/rdebug +415 -0
- data/cli/ruby-debug.rb +176 -0
- data/cli/ruby-debug/command.rb +228 -0
- data/cli/ruby-debug/commands/breakpoints.rb +153 -0
- data/cli/ruby-debug/commands/catchpoint.rb +55 -0
- data/cli/ruby-debug/commands/condition.rb +49 -0
- data/cli/ruby-debug/commands/continue.rb +38 -0
- data/cli/ruby-debug/commands/control.rb +107 -0
- data/cli/ruby-debug/commands/display.rb +120 -0
- data/cli/ruby-debug/commands/edit.rb +48 -0
- data/cli/ruby-debug/commands/enable.rb +202 -0
- data/cli/ruby-debug/commands/eval.rb +176 -0
- data/cli/ruby-debug/commands/finish.rb +42 -0
- data/cli/ruby-debug/commands/frame.rb +301 -0
- data/cli/ruby-debug/commands/help.rb +56 -0
- data/cli/ruby-debug/commands/info.rb +469 -0
- data/cli/ruby-debug/commands/irb.rb +123 -0
- data/cli/ruby-debug/commands/kill.rb +51 -0
- data/cli/ruby-debug/commands/list.rb +94 -0
- data/cli/ruby-debug/commands/method.rb +84 -0
- data/cli/ruby-debug/commands/quit.rb +39 -0
- data/cli/ruby-debug/commands/reload.rb +40 -0
- data/cli/ruby-debug/commands/save.rb +90 -0
- data/cli/ruby-debug/commands/set.rb +237 -0
- data/cli/ruby-debug/commands/show.rb +253 -0
- data/cli/ruby-debug/commands/source.rb +36 -0
- data/cli/ruby-debug/commands/stepping.rb +81 -0
- data/cli/ruby-debug/commands/threads.rb +189 -0
- data/cli/ruby-debug/commands/tmate.rb +36 -0
- data/cli/ruby-debug/commands/trace.rb +57 -0
- data/cli/ruby-debug/commands/variables.rb +199 -0
- data/cli/ruby-debug/debugger.rb +5 -0
- data/cli/ruby-debug/helper.rb +69 -0
- data/cli/ruby-debug/interface.rb +232 -0
- data/cli/ruby-debug/processor.rb +474 -0
- data/rdbg.rb +33 -0
- metadata +122 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'irb'
|
2
|
+
|
3
|
+
module IRB # :nodoc:
|
4
|
+
module ExtendCommand # :nodoc:
|
5
|
+
class Continue # :nodoc:
|
6
|
+
def self.execute(conf)
|
7
|
+
throw :IRB_EXIT, :cont
|
8
|
+
end
|
9
|
+
end
|
10
|
+
class Next # :nodoc:
|
11
|
+
def self.execute(conf)
|
12
|
+
throw :IRB_EXIT, :next
|
13
|
+
end
|
14
|
+
end
|
15
|
+
class Step # :nodoc:
|
16
|
+
def self.execute(conf)
|
17
|
+
throw :IRB_EXIT, :step
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
ExtendCommandBundle.def_extend_command "cont", :Continue
|
22
|
+
ExtendCommandBundle.def_extend_command "n", :Next
|
23
|
+
ExtendCommandBundle.def_extend_command "step", :Step
|
24
|
+
|
25
|
+
def self.start_session(binding)
|
26
|
+
unless @__initialized
|
27
|
+
args = ARGV.dup
|
28
|
+
ARGV.replace([])
|
29
|
+
IRB.setup(nil)
|
30
|
+
ARGV.replace(args)
|
31
|
+
@__initialized = true
|
32
|
+
end
|
33
|
+
|
34
|
+
workspace = WorkSpace.new(binding)
|
35
|
+
|
36
|
+
irb = Irb.new(workspace)
|
37
|
+
|
38
|
+
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
39
|
+
@CONF[:MAIN_CONTEXT] = irb.context
|
40
|
+
|
41
|
+
catch(:IRB_EXIT) do
|
42
|
+
irb.eval_input
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Debugger
|
48
|
+
|
49
|
+
# Implements debugger "irb" command.
|
50
|
+
class IRBCommand < Command
|
51
|
+
|
52
|
+
register_setting_get(:autoirb) do
|
53
|
+
IRBCommand.always_run
|
54
|
+
end
|
55
|
+
register_setting_set(:autoirb) do |value|
|
56
|
+
IRBCommand.always_run = value
|
57
|
+
end
|
58
|
+
|
59
|
+
def regexp
|
60
|
+
/^\s* irb
|
61
|
+
(?:\s+(-d))?
|
62
|
+
\s*$/x
|
63
|
+
end
|
64
|
+
|
65
|
+
def execute
|
66
|
+
unless @state.interface.kind_of?(LocalInterface)
|
67
|
+
print "Command is available only in local mode.\n"
|
68
|
+
throw :debug_error
|
69
|
+
end
|
70
|
+
|
71
|
+
save_trap = trap("SIGINT") do
|
72
|
+
throw :IRB_EXIT, :cont if $rdebug_in_irb
|
73
|
+
end
|
74
|
+
|
75
|
+
add_debugging = @match.is_a?(Array) && '-d' == @match[1]
|
76
|
+
$rdebug_state = @state if add_debugging
|
77
|
+
$rdebug_in_irb = true
|
78
|
+
cont = IRB.start_session(get_binding)
|
79
|
+
case cont
|
80
|
+
when :cont
|
81
|
+
@state.proceed
|
82
|
+
when :step
|
83
|
+
force = Command.settings[:force_stepping]
|
84
|
+
@state.context.step(1, force)
|
85
|
+
@state.proceed
|
86
|
+
when :next
|
87
|
+
force = Command.settings[:force_stepping]
|
88
|
+
@state.context.step_over(1, @state.frame_pos, force)
|
89
|
+
@state.proceed
|
90
|
+
else
|
91
|
+
file = @state.context.frame_file(0)
|
92
|
+
line = @state.context.frame_line(0)
|
93
|
+
CommandProcessor.print_location_and_text(file, line)
|
94
|
+
@state.previous_line = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
ensure
|
98
|
+
$rdebug_in_irb = nil
|
99
|
+
$rdebug_state = nil if add_debugging
|
100
|
+
trap("SIGINT", save_trap) if save_trap
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
def help_command
|
105
|
+
'irb'
|
106
|
+
end
|
107
|
+
|
108
|
+
def help(cmd)
|
109
|
+
%{
|
110
|
+
irb [-d]\tstarts an Interactive Ruby (IRB) session.
|
111
|
+
|
112
|
+
If -d is added you can get access to debugger state via the global variable
|
113
|
+
$RDEBUG_state.
|
114
|
+
|
115
|
+
irb is extended with methods "cont", "n" and "step" which
|
116
|
+
run the corresponding debugger commands. In contrast to the real debugger
|
117
|
+
commands these commands don't allow command arguments.
|
118
|
+
}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Debugger
|
2
|
+
|
3
|
+
# Implements debugger "kill" command
|
4
|
+
class KillCommand < Command
|
5
|
+
self.allow_in_control = true
|
6
|
+
|
7
|
+
def regexp
|
8
|
+
/ ^\s*
|
9
|
+
(?:kill) \s*
|
10
|
+
(?:\s+(\S+))?\s*
|
11
|
+
$
|
12
|
+
/ix
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
puts @match[1]
|
17
|
+
if @match[1]
|
18
|
+
signame = @match[1]
|
19
|
+
unless Signal.list.member?(signame)
|
20
|
+
errmsg("signal name #{signame} is not a signal I know about\n")
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
if 'KILL' == signame
|
24
|
+
@state.interface.finalize
|
25
|
+
end
|
26
|
+
else
|
27
|
+
if not confirm("Really kill? (y/n) ")
|
28
|
+
return
|
29
|
+
else
|
30
|
+
signame = 'KILL'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Process.kill(signame, Process.pid)
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def help_command
|
38
|
+
%w[kill]
|
39
|
+
end
|
40
|
+
|
41
|
+
def help(cmd)
|
42
|
+
%{
|
43
|
+
kill [SIGNAL]
|
44
|
+
|
45
|
+
Send [signal] to Process.pid
|
46
|
+
Equivalent of Process.kill(Process.pid)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Debugger
|
2
|
+
# Implements debugger "list" command.
|
3
|
+
class ListCommand < Command
|
4
|
+
|
5
|
+
register_setting_get(:autolist) do
|
6
|
+
ListCommand.always_run
|
7
|
+
end
|
8
|
+
register_setting_set(:autolist) do |value|
|
9
|
+
ListCommand.always_run = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def regexp
|
13
|
+
/^\s* l(?:ist)? (?:\s*([-=])|\s+(.+))? $/x
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
listsize = Command.settings[:listsize]
|
18
|
+
if !@match || !(@match[1] || @match[2])
|
19
|
+
b = @state.previous_line ?
|
20
|
+
@state.previous_line + listsize : @state.line - (listsize/2)
|
21
|
+
e = b + listsize - 1
|
22
|
+
elsif @match[1] == '-'
|
23
|
+
b = if @state.previous_line
|
24
|
+
if @state.previous_line > 0
|
25
|
+
@state.previous_line - listsize
|
26
|
+
else
|
27
|
+
@state.previous_line
|
28
|
+
end
|
29
|
+
else
|
30
|
+
@state.line - (listsize/2)
|
31
|
+
end
|
32
|
+
e = b + listsize - 1
|
33
|
+
elsif @match[1] == '='
|
34
|
+
@state.previous_line = nil
|
35
|
+
b = @state.line - (listsize/2)
|
36
|
+
e = b + listsize -1
|
37
|
+
else
|
38
|
+
b, e = @match[2].split(/[-,]/)
|
39
|
+
if e
|
40
|
+
b = b.to_i
|
41
|
+
e = e.to_i
|
42
|
+
else
|
43
|
+
b = b.to_i - (listsize/2)
|
44
|
+
e = b + listsize - 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@state.previous_line = display_list(b, e, @state.file, @state.line)
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
def help_command
|
52
|
+
'list'
|
53
|
+
end
|
54
|
+
|
55
|
+
def help(cmd)
|
56
|
+
%{
|
57
|
+
l[ist]\t\tlist forward
|
58
|
+
l[ist] -\tlist backward
|
59
|
+
l[ist] =\tlist current line
|
60
|
+
l[ist] nn-mm\tlist given lines
|
61
|
+
* NOTE - to turn on autolist, use 'set autolist'
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Show FILE from line B to E where CURRENT is the current line number.
|
69
|
+
# If we can show from B to E then we return B, otherwise we return the
|
70
|
+
# previous line @state.previous_line.
|
71
|
+
def display_list(b, e, file, current)
|
72
|
+
print "[%d, %d] in %s\n", b, e, file
|
73
|
+
lines = LineCache::getlines(file,
|
74
|
+
Command.settings[:reload_source_on_change])
|
75
|
+
if lines
|
76
|
+
return @state.previous_line if b >= lines.size
|
77
|
+
e = lines.size if lines.size < e
|
78
|
+
[b, 1].max.upto(e) do |n|
|
79
|
+
if n > 0 && lines[n-1]
|
80
|
+
if n == current
|
81
|
+
print "=> %d %s\n", n, lines[n-1].chomp
|
82
|
+
else
|
83
|
+
print " %d %s\n", n, lines[n-1].chomp
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
else
|
88
|
+
errmsg "No sourcefile available for %s\n", file
|
89
|
+
return @state.previous_line
|
90
|
+
end
|
91
|
+
return e == lines.size ? @state.previous_line : b
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Debugger
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'methodsig'
|
5
|
+
have_methodsig = true
|
6
|
+
rescue LoadError
|
7
|
+
have_methodsig = false
|
8
|
+
end
|
9
|
+
|
10
|
+
# Implements the debugger 'method sig' command.
|
11
|
+
class MethodSigCommand < Command
|
12
|
+
def regexp
|
13
|
+
/^\s*m(?:ethod)?\s+sig(?:nature)?\s+(\S+)\s*$/
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
obj = debug_eval('method(:%s)' % @match[1])
|
18
|
+
if obj.is_a?(Method)
|
19
|
+
begin
|
20
|
+
print "%s\n", obj.signature.to_s
|
21
|
+
rescue
|
22
|
+
errmsg("Can't get signature for '#{@match[1]}'\n")
|
23
|
+
end
|
24
|
+
else
|
25
|
+
errmsg("Can't make method out of '#{@match[1]}'\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def help_command
|
31
|
+
'method'
|
32
|
+
end
|
33
|
+
|
34
|
+
def help(cmd)
|
35
|
+
%{
|
36
|
+
m[ethod] sig[nature] <obj>\tshow the signature of a method
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end if have_methodsig
|
41
|
+
|
42
|
+
# Implements the debugger 'method' command.
|
43
|
+
class MethodCommand < Command
|
44
|
+
def regexp
|
45
|
+
/^\s*m(?:ethod)?\s+((iv)|(i(:?nstance\s+)?)\s+)?/
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute
|
49
|
+
if @match[1] == "iv"
|
50
|
+
obj = debug_eval(@match.post_match)
|
51
|
+
obj.instance_variables.sort.each do |v|
|
52
|
+
print "%s = %s\n", v, obj.instance_variable_get(v).inspect
|
53
|
+
end
|
54
|
+
elsif @match[1]
|
55
|
+
obj = debug_eval(@match.post_match)
|
56
|
+
print "%s\n", columnize(obj.methods.sort(),
|
57
|
+
self.class.settings[:width])
|
58
|
+
else
|
59
|
+
obj = debug_eval(@match.post_match)
|
60
|
+
unless obj.kind_of? Module
|
61
|
+
print "Should be Class/Module: %s\n", @match.post_match
|
62
|
+
else
|
63
|
+
print "%s\n", columnize(obj.instance_methods(false).sort(),
|
64
|
+
self.class.settings[:width])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
def help_command
|
71
|
+
'method'
|
72
|
+
end
|
73
|
+
|
74
|
+
def help(cmd)
|
75
|
+
%{
|
76
|
+
m[ethod] i[nstance] <obj>\tshow methods of object
|
77
|
+
m[ethod] iv <obj>\t\tshow instance variables of object
|
78
|
+
m[ethod] <class|module>\t\tshow instance methods of class or module
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Debugger
|
2
|
+
|
3
|
+
# Implements debugger "quit" command
|
4
|
+
class QuitCommand < Command
|
5
|
+
self.allow_in_control = true
|
6
|
+
|
7
|
+
def regexp
|
8
|
+
/ ^\s*
|
9
|
+
(?:q(?:uit)?|exit) \s*
|
10
|
+
(!|\s+unconditionally)? \s*
|
11
|
+
$
|
12
|
+
/ix
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
if @match[1] or confirm("Really quit? (y/n) ")
|
17
|
+
@state.interface.finalize
|
18
|
+
exit! # exit -> exit!: No graceful way to stop threads...
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def help_command
|
24
|
+
%w[quit exit]
|
25
|
+
end
|
26
|
+
|
27
|
+
def help(cmd)
|
28
|
+
%{
|
29
|
+
q[uit] [!|unconditionally]\texit from debugger.
|
30
|
+
exit[!]\talias to quit
|
31
|
+
|
32
|
+
Normally we prompt before exiting. However if the parameter
|
33
|
+
"unconditionally" or is given or suffixed with !, we stop
|
34
|
+
without asking further questions.
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Debugger
|
2
|
+
# Implements debugger "reload" command.
|
3
|
+
class ReloadCommand < Command
|
4
|
+
self.allow_in_control = true
|
5
|
+
|
6
|
+
register_setting_get(:reload_source_on_change) do
|
7
|
+
Debugger.reload_source_on_change
|
8
|
+
end
|
9
|
+
register_setting_set(:reload_source_on_change) do |value|
|
10
|
+
Debugger.reload_source_on_change = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def regexp
|
14
|
+
/^\s*r(?:eload)?$/
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
Debugger.source_reload
|
19
|
+
print "Source code is reloaded. Automatic reloading is #{source_reloading}.\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def source_reloading
|
25
|
+
Debugger.reload_source_on_change ? 'on' : 'off'
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def help_command
|
30
|
+
'reload'
|
31
|
+
end
|
32
|
+
|
33
|
+
def help(cmd)
|
34
|
+
%{
|
35
|
+
r[eload]\tforces source code reloading
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Debugger
|
2
|
+
module SaveFunctions # :nodoc:
|
3
|
+
|
4
|
+
# Create a temporary file to write in if file is nil
|
5
|
+
def open_save
|
6
|
+
require "tempfile"
|
7
|
+
file = Tempfile.new("rdebug-save")
|
8
|
+
# We want close to not unlink, so redefine.
|
9
|
+
def file.close
|
10
|
+
@tmpfile.close if @tmpfile
|
11
|
+
end
|
12
|
+
return file
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class SaveCommand < Command # :nodoc:
|
17
|
+
self.allow_in_control = true
|
18
|
+
|
19
|
+
def save_breakpoints(file)
|
20
|
+
Debugger.breakpoints.each do |b|
|
21
|
+
file.puts "break #{b.source}:#{b.pos}#{" if #{b.expr}" if b.expr}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def save_catchpoints(file)
|
26
|
+
Debugger.catchpoints.keys.each do |c|
|
27
|
+
file.puts "catch #{c}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def save_displays(file)
|
32
|
+
for d in @state.display
|
33
|
+
if d[0]
|
34
|
+
file.puts "display #{d[1]}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def save_settings(file)
|
40
|
+
# FIXME put routine in set
|
41
|
+
%w(autoeval basename debuggertesting).each do |setting|
|
42
|
+
on_off = show_onoff(Command.settings[setting.to_sym])
|
43
|
+
file.puts "set #{setting} #{on_off}"
|
44
|
+
end
|
45
|
+
%w(autolist autoirb).each do |setting|
|
46
|
+
on_off = show_onoff(Command.settings[setting.to_sym] > 0)
|
47
|
+
file.puts "set #{setting} #{on_off}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def regexp
|
52
|
+
/^\s* sa(?:ve)?
|
53
|
+
(?:\s+(.+))?
|
54
|
+
\s*$/ix
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute
|
58
|
+
if not @match[1] or @match[1].strip.empty?
|
59
|
+
file = open_save()
|
60
|
+
else
|
61
|
+
file = open(@match[1], 'w')
|
62
|
+
end
|
63
|
+
save_breakpoints(file)
|
64
|
+
save_catchpoints(file)
|
65
|
+
# save_displays(file)
|
66
|
+
save_settings(file)
|
67
|
+
print "Saved to '#{file.path}'\n"
|
68
|
+
if @state and @state.interface
|
69
|
+
@state.interface.restart_file = file.path
|
70
|
+
end
|
71
|
+
file.close
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def help_command
|
76
|
+
'save'
|
77
|
+
end
|
78
|
+
|
79
|
+
def help(cmd)
|
80
|
+
%{
|
81
|
+
save [FILE]
|
82
|
+
Saves current debugger state to FILE as a script file.
|
83
|
+
This includes breakpoints, catchpoints, display expressions and some settings.
|
84
|
+
If no filename is given, we will fabricate one.
|
85
|
+
|
86
|
+
Use the 'source' command in another debug session to restore them.}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|