ruby-debug 0.3-mswin32 → 0.4-mswin32

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,15 @@
1
+ 0.4
2
+ - Debugger.start method takes a block. If a block is specified, this method starts debugger, yields to the block
3
+ and stops debugger at the end.
4
+ - 'tm[ate]' command accepts a frame number now.
5
+ - 'list' command accepts on/off parameter which controls whether listing will be displayed on every stop.
6
+ - 'eval on/off' controls the evaluation of unknown command.
7
+ - Debugger reads readline history file .rdebug_hist at startup and saves it at exit.
8
+ - 'sa[ve] <file>' command can be used to save current breackpoints and catchpoint if any
9
+ - 'sc[ript] <file' command can be used to run script file. Script files can contain only control commands.
10
+ - rdebug script accepts '--script FILE' parameter.
11
+ - thread commands are available for the control port.
12
+
1
13
  0.3 (2006-08-07)
2
14
  - Renamed Debugger.start_server to Debugger.start_remote.
3
15
  - Debugger.start_remote activates debugger by calling Debugger.start.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/rdoctask'
5
5
  SO_NAME = "ruby_debug.so"
6
6
 
7
7
  # ------- Default Package ----------
8
- RUBY_DEBUG_VERSION = "0.3"
8
+ RUBY_DEBUG_VERSION = "0.4"
9
9
 
10
10
  FILES = FileList[
11
11
  'Rakefile',
data/bin/rdebug CHANGED
@@ -12,7 +12,8 @@ options = OpenStruct.new(
12
12
  'port' => Debugger::PORT,
13
13
  'cport' => Debugger::PORT + 1,
14
14
  'wait' => false,
15
- 'nostop' => false
15
+ 'nostop' => false,
16
+ 'script' => nil
16
17
  )
17
18
 
18
19
  opts = OptionParser.new do |opts|
@@ -28,6 +29,12 @@ EOB
28
29
  opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
29
30
  opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
30
31
  opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
32
+ opts.on("--script FILE", String, "Name of the script file to run") do |options.script|
33
+ unless File.exists?(options.script)
34
+ puts "Script file '#{options.script}' is not found"
35
+ exit
36
+ end
37
+ end
31
38
  opts.on("--cport PORT", Integer, "Port used for contol commands, implies -s option") {|options.port|}
32
39
  opts.separator ""
33
40
  opts.separator "Common options:"
@@ -67,6 +74,9 @@ else
67
74
  Debugger.start_remote(options.host, [options.port, options.cport])
68
75
  else
69
76
  Debugger.start
77
+ if options.script
78
+ Debugger.run_script(options.script)
79
+ end
70
80
  debugger 2
71
81
  end
72
82
  load ARGV.shift
data/ext/ruby_debug.c CHANGED
@@ -4,7 +4,7 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.3"
7
+ #define DEBUG_VERSION "0.4"
8
8
 
9
9
  typedef struct {
10
10
  int thnum;
@@ -62,16 +62,18 @@ static VALUE debug_suspend(VALUE);
62
62
  static VALUE create_binding(VALUE);
63
63
  static VALUE debug_stop(VALUE);
64
64
 
65
+ #define IS_STARTED (threads_tbl != Qnil)
66
+
65
67
  static VALUE
66
68
  debug_is_started(VALUE self)
67
69
  {
68
- return threads_tbl != Qnil ? Qtrue : Qfalse;
70
+ return IS_STARTED ? Qtrue : Qfalse;
69
71
  }
70
72
 
71
73
  static void
72
74
  debug_check_started()
73
75
  {
74
- if(threads_tbl == Qnil)
76
+ if(!IS_STARTED)
75
77
  {
76
78
  rb_raise(rb_eRuntimeError, "Debugger.start is not called yet.");
77
79
  }
@@ -181,7 +183,7 @@ call_at_line_unprotected(VALUE args)
181
183
  {
182
184
  VALUE context;
183
185
  context = *RARRAY(args)->ptr;
184
- rb_funcall2(context, idAtLine, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1);
186
+ return rb_funcall2(context, idAtLine, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1);
185
187
  }
186
188
 
187
189
  static VALUE
@@ -478,9 +480,20 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
478
480
  debugging--;
479
481
  }
480
482
 
483
+ static VALUE
484
+ debug_stop_i(VALUE value)
485
+ {
486
+ if(IS_STARTED)
487
+ debug_stop(value);
488
+ return Qnil;
489
+ }
490
+
481
491
  static VALUE
482
492
  debug_start(VALUE self)
483
493
  {
494
+ if(IS_STARTED)
495
+ return Qnil;
496
+
484
497
  threads_tbl = rb_hash_new();
485
498
  breakpoints = rb_ary_new();
486
499
  waiting = rb_ary_new();
@@ -490,6 +503,10 @@ debug_start(VALUE self)
490
503
  RUBY_EVENT_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_CLASS |
491
504
  RUBY_EVENT_END | RUBY_EVENT_RAISE
492
505
  );
506
+
507
+ if(rb_block_given_p())
508
+ return rb_ensure(rb_yield, Qnil, debug_stop_i, Qnil);
509
+
493
510
  return Qnil;
494
511
  }
495
512
 
data/lib/ruby-debug.rb CHANGED
@@ -89,7 +89,7 @@ module Debugger
89
89
  cmd_port, ctrl_port = port, port + 1
90
90
  end
91
91
 
92
- @control_tread = Thread.start do
92
+ @control_thread = Thread.start do
93
93
  server = TCPServer.new(host, ctrl_port)
94
94
  while (session = server.accept)
95
95
  interface = RemoteInterface.new(session)
@@ -176,6 +176,13 @@ module Debugger
176
176
  end
177
177
  return "\n"
178
178
  end
179
+
180
+ # runs a script file
181
+ def run_script(file, out = processor.interface)
182
+ interface = ScriptInterface.new(file, out)
183
+ processor = ControlCommandProcessor.new(interface)
184
+ processor.process_commands
185
+ end
179
186
  end
180
187
  end
181
188
 
@@ -5,11 +5,17 @@ module Debugger
5
5
  @commands ||= []
6
6
  end
7
7
 
8
+ DEF_OPTIONS = {
9
+ :event => true,
10
+ :control => false,
11
+ :always_run => false,
12
+ :unknown => false,
13
+ }
14
+
8
15
  def inherited(klass)
9
- klass.instance_variable_set("@event",
10
- klass.instance_variable_get("@event") || true)
11
- klass.instance_variable_set("@control",
12
- klass.instance_variable_get("@control") || false)
16
+ DEF_OPTIONS.each do |o, v|
17
+ klass.options[o] = v if klass.options[o].nil?
18
+ end
13
19
  commands << klass
14
20
  end
15
21
 
@@ -20,8 +26,21 @@ module Debugger
20
26
  end
21
27
  end
22
28
 
23
- attr_accessor :control
24
- attr_accessor :event
29
+ def method_missing(meth, *args, &block)
30
+ if meth.to_s =~ /^(.+?)=$/
31
+ @options[$1.intern] = args.first
32
+ else
33
+ if @options.has_key?(meth)
34
+ @options[meth]
35
+ else
36
+ super
37
+ end
38
+ end
39
+ end
40
+
41
+ def options
42
+ @options ||= {}
43
+ end
25
44
  end
26
45
 
27
46
  def initialize(state)
@@ -8,6 +8,7 @@ module Debugger
8
8
 
9
9
  def execute
10
10
  if confirm("Really quit? (y/n) ")
11
+ Debugger.save_history if Debugger.respond_to? :save_history
11
12
  exit! # exit -> exit!: No graceful way to stop threads...
12
13
  end
13
14
  end
@@ -33,6 +33,7 @@ module Debugger
33
33
  end
34
34
 
35
35
  class DisplayCommand < Command
36
+ self.always_run = true
36
37
  include DisplayFunctions
37
38
 
38
39
  def initialize(state)
@@ -1,11 +1,22 @@
1
1
  module Debugger
2
2
  class EvalCommand < Command
3
+ def match(input)
4
+ @input = input
5
+ super
6
+ end
7
+
3
8
  def regexp
4
- /^\s*(\s*p|e(?:val)?)\s+/
9
+ /^\s*(p|e(?:val)?)(?:\s+(on|off)|\s+)/
5
10
  end
6
11
 
7
12
  def execute
8
- print "%s\n", debug_eval(@match.post_match).inspect
13
+ if @match && @match[1] != 'p' && %w[on off].include?(@match[2])
14
+ self.class.unknown = @match[2] == 'on'
15
+ print "Evaluation of unknown command is #{self.class.unknown ? 'on': 'off'}.\n"
16
+ return
17
+ end
18
+ expr = @match ? @match.post_match : @input
19
+ print "%s\n", debug_eval(expr).inspect
9
20
  end
10
21
 
11
22
  class << self
@@ -21,7 +32,8 @@ module Debugger
21
32
  else
22
33
  %{
23
34
  e[val] expression\tevaluate expression and print its value,
24
- \t\t\talias for p
35
+ \t\t\talias for p.
36
+ e[val] on/off\t\twhen 'on', debugger will evaluate every unknown command.
25
37
  }
26
38
  end
27
39
  end
@@ -1,11 +1,11 @@
1
1
  module Debugger
2
2
  class ListCommand < Command
3
3
  def regexp
4
- /^\s*l(?:ist)?(?:\s+(.+))?$/
4
+ /^\s*l(?:ist)?(?:\s*(.+))?$/
5
5
  end
6
6
 
7
7
  def execute
8
- if not @match[1]
8
+ if !@match || !@match[1]
9
9
  b = @state.previous_line ? @state.previous_line + 10 : @state.line - 5
10
10
  e = b + 9
11
11
  elsif @match[1] == '-'
@@ -15,6 +15,14 @@ module Debugger
15
15
  @state.previous_line = nil
16
16
  b = @state.line - 5
17
17
  e = b + 9
18
+ elsif @match[1] == 'on'
19
+ self.class.always_run = true
20
+ print "Listing is on.\n"
21
+ return
22
+ elsif @match[1] == 'off'
23
+ self.class.always_run = false
24
+ print "Listing is off.\n"
25
+ return
18
26
  else
19
27
  b, e = @match[1].split(/[-,]/)
20
28
  if e
@@ -40,6 +48,7 @@ module Debugger
40
48
  l[ist] -\tlist backward
41
49
  l[ist] =\tlist current line
42
50
  l[ist] nn-mm\tlist given lines
51
+ l[ist] on/off\tprint listing on every stop
43
52
  }
44
53
  end
45
54
  end
@@ -0,0 +1,59 @@
1
+ module Debugger
2
+ class ScriptCommand < Command
3
+ self.control = true
4
+
5
+ def regexp
6
+ /^\s*sc(?:ript)?\s+(.+)$/
7
+ end
8
+
9
+ def execute
10
+ unless File.exists?(@match[1])
11
+ print "Script file '#{@match[1]}' is not found\n"
12
+ return
13
+ end
14
+ Debugger.run_script(@match[1], @state)
15
+ end
16
+
17
+ class << self
18
+ def help_command
19
+ 'script'
20
+ end
21
+
22
+ def help(cmd)
23
+ %{
24
+ script FILE\texecutes a script file
25
+ }
26
+ end
27
+ end
28
+ end
29
+
30
+ class SaveCommand < Command
31
+ self.control = true
32
+
33
+ def regexp
34
+ /^\s*sa(?:ve)?\s+(.+)$/
35
+ end
36
+
37
+ def execute
38
+ open(@match[1], 'w') do |file|
39
+ Debugger.breakpoints.each do |b|
40
+ file.puts "break #{b.source}:#{b.pos}#{" if #{b.expr}" if b.expr}"
41
+ end
42
+ file.puts "catch #{Debugger.catchpoint}" if Debugger.catchpoint
43
+ end
44
+ print "Saved to '#{@match[1]}'\n"
45
+ end
46
+
47
+ class << self
48
+ def help_command
49
+ 'save'
50
+ end
51
+
52
+ def help(cmd)
53
+ %{
54
+ save FILE\tsaves current breakpoints and catchpoint as a script file
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,11 +1,9 @@
1
1
  module Debugger
2
2
  module ThreadFunctions
3
3
  def display_context(c)
4
- if c.thread == Thread.current
5
- print "+"
6
- else
7
- print " "
8
- end
4
+ c_flag = c.thread == Thread.current ? '+' : ' '
5
+ d_flag = debugger_thread?(c) ? '!' : ' '
6
+ print "%s%s", c_flag, d_flag
9
7
  print "%d ", c.thnum
10
8
  print "%s\t", c.thread.inspect
11
9
  last_frame = c.frames.first
@@ -14,9 +12,14 @@ module Debugger
14
12
  end
15
13
  print "\n"
16
14
  end
15
+
16
+ def debugger_thread?(c)
17
+ [Debugger.thread, Debugger.control_thread].include?(c.thread)
18
+ end
17
19
  end
18
20
 
19
21
  class ThreadListCommand < Command
22
+ self.control = true
20
23
  include ThreadFunctions
21
24
 
22
25
  def regexp
@@ -43,6 +46,7 @@ module Debugger
43
46
  end
44
47
 
45
48
  class ThreadSwitchCommand < Command
49
+ self.control = true
46
50
  include ThreadFunctions
47
51
 
48
52
  def regexp
@@ -51,8 +55,11 @@ module Debugger
51
55
 
52
56
  def execute
53
57
  c = get_context(@match[1].to_i)
54
- if c == @state.context
58
+ case
59
+ when c == @state.context
55
60
  print "It's the current thread.\n"
61
+ when debugger_thread?(c)
62
+ print "Can't switch to the debugger thread.\n"
56
63
  else
57
64
  display_context(c)
58
65
  c.stop_next = 1
@@ -75,6 +82,7 @@ module Debugger
75
82
  end
76
83
 
77
84
  class ThreadStopCommand < Command
85
+ self.control = true
78
86
  include ThreadFunctions
79
87
 
80
88
  def regexp
@@ -83,9 +91,12 @@ module Debugger
83
91
 
84
92
  def execute
85
93
  c = get_context(@match[1].to_i)
86
- if c == @state.context
94
+ case
95
+ when c == @state.context
87
96
  print "It's the current thread.\n"
88
- elsif c.thread.stop?
97
+ when debugger_thread?(c)
98
+ print "Can't stop the debugger thread.\n"
99
+ when c.thread.stop?
89
100
  print "Already stopped.\n"
90
101
  else
91
102
  display_context(c)
@@ -131,6 +142,7 @@ module Debugger
131
142
  end
132
143
 
133
144
  class ThreadResumeCommand < Command
145
+ self.control = true
134
146
  include ThreadFunctions
135
147
 
136
148
  def regexp
@@ -139,9 +151,12 @@ module Debugger
139
151
 
140
152
  def execute
141
153
  c = get_context(@match[1].to_i)
142
- if c == @state.context
154
+ case
155
+ when c == @state.context
143
156
  print "It's the current thread.\n"
144
- elsif !c.thread.stop?
157
+ when debugger_thread?(c)
158
+ print "Can't resume the debugger thread.\n"
159
+ when !c.thread.stop?
145
160
  print "Already running."
146
161
  else
147
162
  display_context(c)
@@ -2,11 +2,22 @@ module Debugger
2
2
  if RUBY_PLATFORM =~ /darwin/
3
3
  class TextMateCommand < Command
4
4
  def regexp
5
- /^\s*tm(?:ate)?$/
5
+ /^\s*tm(?:ate)?(?:\s*(\d+))?$/
6
6
  end
7
7
 
8
8
  def execute
9
- %x|open 'txmt://open?url=file://#{File.expand_path(@state.file)}&line=#{@state.line}'|
9
+ if @match[1]
10
+ frm_n = @match[1].to_i
11
+ if frm_n > @state.context.frames.size || frm_n == 0
12
+ print "Wrong frame number\n"
13
+ return
14
+ end
15
+ frame = @state.context.frames[frm_n - 1]
16
+ file, line = frame.file, frame.line
17
+ else
18
+ file, line = @state.file, @state.line
19
+ end
20
+ %x|open 'txmt://open?url=file://#{File.expand_path(file)}&line=#{line}'|
10
21
  end
11
22
 
12
23
  class << self
@@ -16,7 +27,8 @@ module Debugger
16
27
 
17
28
  def help(cmd)
18
29
  %{
19
- tm[ate]\topens a current file in TextMate
30
+ tm[ate] n\topens a current file in TextMate.
31
+ \t\tIt uses n-th frame if arg (n) is specifed.
20
32
  }
21
33
  end
22
34
  end
@@ -19,6 +19,26 @@ module Debugger
19
19
 
20
20
  begin
21
21
  require 'readline'
22
+ FILE_HISTORY = ".rdebug_hist"
23
+
24
+ save_file = File.join(Dir.getwd, FILE_HISTORY)
25
+ open(save_file, 'r') do |file|
26
+ file.each do |line|
27
+ line.chomp!
28
+ Readline::HISTORY << line
29
+ end
30
+ end if File.exists?(save_file)
31
+
32
+ class << Debugger; self end.send('define_method', 'save_history') do
33
+ open(save_file, 'w') do |file|
34
+ Readline::HISTORY.each do |line|
35
+ file.puts line
36
+ end
37
+ end
38
+ end
39
+ class << Debugger; public :save_history end
40
+ at_exit { Debugger.save_history }
41
+
22
42
  def readline(prompt, hist)
23
43
  Readline::readline(prompt, hist)
24
44
  end
@@ -66,4 +86,33 @@ module Debugger
66
86
  result.chomp
67
87
  end
68
88
  end
89
+
90
+ class ScriptInterface
91
+ def initialize(file, out)
92
+ @file = open(file)
93
+ @out = out
94
+ end
95
+
96
+ def read_command(prompt)
97
+ while result = @file.gets
98
+ next if result =~ /^\s*#/
99
+ next if result.strip.empty?
100
+ break
101
+ end
102
+ raise IOError unless result
103
+ result
104
+ end
105
+
106
+ def confirm(prompt)
107
+ 'y'
108
+ end
109
+
110
+ def print(*args)
111
+ @out.print(*args)
112
+ end
113
+
114
+ def close
115
+ @file.close
116
+ end
117
+ end
69
118
  end
@@ -85,7 +85,7 @@ module Debugger
85
85
  s.commands = event_cmds
86
86
  end
87
87
  commands = event_cmds.map{|cmd| cmd.new(state) }
88
- commands.find{ |cmd| cmd.kind_of?(DisplayCommand) }.execute
88
+ commands.select{|cmd| cmd.class.always_run }.each{|cmd| cmd.execute }
89
89
 
90
90
  while !state.proceed? and input = @interface.read_command("(rdb:%d) " % context.thnum)
91
91
  catch(:debug_error) do
@@ -99,7 +99,12 @@ module Debugger
99
99
  if cmd = commands.find{ |c| c.match(input) }
100
100
  cmd.execute
101
101
  else
102
- print "Unknown command\n"
102
+ unknown_cmd = commands.find{|cmd| cmd.class.unknown }
103
+ if unknown_cmd
104
+ unknown_cmd.execute
105
+ else
106
+ print "Unknown command\n"
107
+ end
103
108
  end
104
109
  end
105
110
  end
@@ -161,6 +166,8 @@ module Debugger
161
166
  rescue Exception
162
167
  print "INTERNAL ERROR!!! #{$!}\n"
163
168
  print $!.backtrace.map{|l| "\t#{l}"}.join("\n")
169
+ ensure
170
+ @interface.close
164
171
  end
165
172
 
166
173
  class State
@@ -180,6 +187,10 @@ module Debugger
180
187
  def confirm(*args)
181
188
  'y'
182
189
  end
190
+
191
+ def context
192
+ nil
193
+ end
183
194
 
184
195
  def file
185
196
  print "No filename given.\n"
data/lib/ruby_debug.so CHANGED
Binary file
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruby-debug
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.3"
7
- date: 2006-08-13 16:55:45 -04:00
6
+ version: "0.4"
7
+ date: 2006-08-24 23:57:48 -04:00
8
8
  summary: Fast Ruby debugger
9
9
  require_paths:
10
10
  - lib
@@ -49,6 +49,7 @@ files:
49
49
  - lib/ruby-debug/commands/help.rb
50
50
  - lib/ruby-debug/commands/list.rb
51
51
  - lib/ruby-debug/commands/method.rb
52
+ - lib/ruby-debug/commands/script.rb
52
53
  - lib/ruby-debug/commands/stepping.rb
53
54
  - lib/ruby-debug/commands/threads.rb
54
55
  - lib/ruby-debug/commands/tmate.rb