ruby-debug 0.3-mswin32 → 0.4-mswin32

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