ruby-debug 0.1.5 → 0.2

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,10 @@
1
+ 0.2 (2006-06-17)
2
+ - Added the remote debugging. It should be activated by calling Debugger#start_server method.
3
+ - CHANGED: In order to activate the debugger, it's not enough to require 'ruby-debug'.
4
+ Debugger#start method must be called explicitly.
5
+ - Debugger used to evaluate anything you enter as long as it's not a command. Starting from
6
+ this version the 'eval' command must be used to evaluate an expression.
7
+
1
8
  0.1.5 (2006-06-13)
2
9
  - Now the check for a breakpoint uses base filename of the source file.
3
10
  - Removed compilation warnings when compiling with -Wall
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.1.5"
8
+ RUBY_DEBUG_VERSION = "0.2"
9
9
 
10
10
  FILES = FileList[
11
11
  'Rakefile',
@@ -48,7 +48,6 @@ EOF
48
48
  spec.has_rdoc = false
49
49
  end
50
50
 
51
-
52
51
  # Rake task to build the default package
53
52
  Rake::GemPackageTask.new(default_spec) do |pkg|
54
53
  pkg.need_tar = true
@@ -57,6 +56,30 @@ end
57
56
 
58
57
  task :default => [:package]
59
58
 
59
+ # Windows specification
60
+ win_spec = default_spec.clone
61
+ win_spec.extensions = []
62
+ win_spec.platform = Gem::Platform::WIN32
63
+ win_spec.files += ["lib/#{SO_NAME}"]
64
+
65
+ desc "Create Windows Gem"
66
+ task :win32_gem do
67
+ # Copy the win32 extension the top level directory
68
+ current_dir = File.expand_path(File.dirname(__FILE__))
69
+ source = File.join(current_dir, "ext", "win32", SO_NAME)
70
+ target = File.join(current_dir, "lib", SO_NAME)
71
+ cp(source, target)
72
+
73
+ # Create the gem, then move it to pkg
74
+ Gem::Builder.new(win_spec).build
75
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
76
+ mv(gem_file, "pkg/#{gem_file}")
77
+
78
+ # Remove win extension fro top level directory
79
+ rm(target)
80
+ end
81
+
82
+
60
83
  desc "Publish ruby-debug to RubyForge."
61
84
  task :publish do
62
85
  require 'rake/contrib/sshpublisher'
data/bin/rdebug CHANGED
@@ -1,13 +1,84 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- if ARGV.empty?
4
- puts "Usage: #{__FILE__} <script>"
5
- exit(1)
6
- end
7
-
8
3
  require 'rubygems'
4
+ require 'optparse'
5
+ require "ostruct"
9
6
  require 'ruby-debug'
10
- trap('INT') { Debugger.interrupt_last }
11
7
 
12
- debugger 2
13
- load ARGV.shift
8
+ options = OpenStruct.new(
9
+ 'server' => false,
10
+ 'client' => false,
11
+ 'host' => nil,
12
+ 'port' => Debugger::PORT
13
+ )
14
+
15
+ opts = OptionParser.new do |opts|
16
+ opts.banner = <<EOB
17
+ ruby-debug #{Debugger::VERSION}
18
+ Usage: rdebug [options] <script.rb> <script.rb parameters>
19
+ EOB
20
+ opts.separator ""
21
+ opts.separator "Options:"
22
+ opts.on("-s", "--server", "Listen for remote connections") {options.server = true}
23
+ opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
24
+ opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
25
+ opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
26
+ opts.separator ""
27
+ opts.separator "Common options:"
28
+ opts.on_tail("--help", "Show this message") do
29
+ puts opts
30
+ exit
31
+ end
32
+ opts.on_tail("-v", "--version", "Show version") do
33
+ puts "ruby-debug #{Debugger::VERSION}"
34
+ exit
35
+ end
36
+ end
37
+
38
+ begin
39
+ opts.parse! ARGV
40
+ rescue StandardError => e
41
+ puts opts
42
+ puts
43
+ puts e.message
44
+ exit(-1)
45
+ end
46
+
47
+ if options.client
48
+ require "socket"
49
+ interface = Debugger::LocalInterface.new
50
+ socket = TCPSocket.new(options.host, options.port)
51
+ puts "Connected."
52
+
53
+ catch(:exit) do
54
+ while (line = socket.gets)
55
+ case line
56
+ when /^PROMPT (.*)$/
57
+ input = interface.read_command($1)
58
+ throw :exit unless input
59
+ socket.puts input
60
+ when /^CONFIRM (.*)$/
61
+ input = interface.confirm($1)
62
+ throw :exit unless input
63
+ socket.puts input
64
+ else
65
+ print line
66
+ end
67
+ end
68
+ end
69
+ socket.close
70
+ puts
71
+ else
72
+ if ARGV.empty?
73
+ puts opts
74
+ puts
75
+ puts "Must specify a script to run"
76
+ exit(-1)
77
+ end
78
+
79
+ trap('INT') { Debugger.interrupt_last }
80
+ Debugger.start_server(options.host, options.port) if options.server
81
+ Debugger.start
82
+ debugger 2
83
+ load ARGV.shift
84
+ end
data/bin/remote ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+ require "ruby-debug/inputs"
5
+
6
+ host = ARGV[0] || "localhost"
7
+ port = 8989
8
+
9
+ input = Debugger::LocalInput.new
10
+ socket = TCPSocket.new(host, port)
11
+ puts "Connected."
12
+
13
+ catch(:exit) do
14
+ while (line = socket.gets)
15
+ case line
16
+ when /^PROMPT (.*)$/
17
+ data = input.read_command($1)
18
+ throw :exit unless data
19
+ socket.puts data
20
+ when /^CONFIRM (.*)$/
21
+ data = input.confirm($1)
22
+ throw :exit unless data
23
+ socket.puts data
24
+ else
25
+ print line
26
+ end
27
+ end
28
+ end
29
+ socket.close
30
+ puts
data/ext/ruby_debug.c CHANGED
@@ -4,13 +4,15 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.1.5"
7
+ #define DEBUG_VERSION "0.2"
8
8
 
9
9
  typedef struct {
10
10
  int thnum;
11
+ VALUE last_file;
12
+ VALUE last_line;
13
+ int moved;
11
14
  int stop_next;
12
15
  int dest_frame;
13
- int src_line;
14
16
  int stop_line;
15
17
  int stop_frame;
16
18
  int suspend;
@@ -43,7 +45,7 @@ static VALUE cContext;
43
45
  static VALUE cFrame;
44
46
  static VALUE cBreakpoint;
45
47
 
46
- static ID idDebugCommand;
48
+ static ID idAtLine;
47
49
  static ID idAtBreakpoint;
48
50
  static ID idAtCatchpoint;
49
51
  static ID idAtTracing;
@@ -81,6 +83,8 @@ debug_context_mark(void* data)
81
83
  debug_context_t *debug_context = (debug_context_t *)data;
82
84
  rb_gc_mark(debug_context->frames);
83
85
  rb_gc_mark(debug_context->thread);
86
+ rb_gc_mark(debug_context->last_file);
87
+ rb_gc_mark(debug_context->last_line);
84
88
  }
85
89
 
86
90
  static VALUE
@@ -91,9 +95,13 @@ debug_context_create(VALUE thread)
91
95
 
92
96
  debug_context = ALLOC(debug_context_t);
93
97
  debug_context-> thnum = ++thnum_max;
98
+
99
+ debug_context->last_file = Qnil;
100
+ debug_context->last_line = Qnil;
101
+ debug_context->moved = 0;
102
+
94
103
  debug_context->stop_next = -1;
95
104
  debug_context->dest_frame = -1;
96
- debug_context->src_line = -1;
97
105
  debug_context->stop_line = -1;
98
106
  debug_context->stop_frame = -1;
99
107
  debug_context->suspend = 0;
@@ -145,16 +153,36 @@ debug_frame_create(VALUE file, VALUE line, VALUE binding, ID id)
145
153
  return result;
146
154
  }
147
155
 
148
- static VALUE
149
- call_debug_command(VALUE context, int thnum, VALUE binding, ID mid, VALUE file, VALUE line)
156
+ static void
157
+ save_current_position(VALUE context)
150
158
  {
151
- VALUE id;
159
+ VALUE cur_frame;
160
+ debug_context_t *debug_context;
161
+ debug_frame_t *debug_frame;
162
+
163
+ Data_Get_Struct(context, debug_context_t, debug_context);
164
+ if(RARRAY(debug_context->frames)->len == 0)
165
+ return;
166
+
167
+ cur_frame = *RARRAY(debug_context->frames)->ptr;
168
+ Data_Get_Struct(cur_frame, debug_frame_t, debug_frame);
169
+
170
+ debug_context->last_file = debug_frame->file;
171
+ debug_context->last_line = debug_frame->line;
172
+ debug_context->moved = 0;
173
+ }
152
174
 
153
- id = mid ? ID2SYM(mid) : Qnil;
175
+ #define did_moved() (debug_context->last_line != line || \
176
+ debug_context->last_file == Qnil || \
177
+ rb_str_cmp(debug_context->last_file, file) != 0)
154
178
 
179
+ static VALUE
180
+ call_at_line(VALUE context, int thnum, VALUE binding, VALUE file, VALUE line)
181
+ {
155
182
  last_debugged_thnum = thnum;
183
+ save_current_position(context);
156
184
  debug_suspend(mDebugger);
157
- return rb_funcall(context, idDebugCommand, 4, file, line, id, binding);
185
+ return rb_funcall(context, idAtLine, 3, file, line, binding);
158
186
  }
159
187
 
160
188
  static void
@@ -189,7 +217,7 @@ basename(VALUE filename)
189
217
  }
190
218
 
191
219
  static int
192
- check_breakpoints(VALUE context, VALUE file, VALUE klass, VALUE pos)
220
+ check_breakpoints(debug_context_t *debug_context, VALUE file, VALUE klass, VALUE pos)
193
221
  {
194
222
  VALUE breakpoint;
195
223
  debug_breakpoint_t *debug_breakpoint;
@@ -197,6 +225,9 @@ check_breakpoints(VALUE context, VALUE file, VALUE klass, VALUE pos)
197
225
 
198
226
  if(RARRAY(breakpoints)->len == 0)
199
227
  return -1;
228
+ if(!debug_context->moved)
229
+ return -1;
230
+
200
231
  for(i = 0; i < RARRAY(breakpoints)->len; i++)
201
232
  {
202
233
  breakpoint = rb_ary_entry(breakpoints, i);
@@ -282,10 +313,12 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
282
313
  debug_context_t *debug_context;
283
314
  VALUE file = Qnil, line = Qnil;
284
315
  int breakpoint_index = -1;
285
-
316
+
286
317
  static int debugging = 0;
287
318
 
319
+ if (mid == ID_ALLOCATOR) return;
288
320
  if(debugging) return;
321
+ if(!node) return;
289
322
 
290
323
  debugging++;
291
324
 
@@ -294,11 +327,11 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
294
327
  Data_Get_Struct(context, debug_context_t, debug_context);
295
328
  check_suspend(debug_context);
296
329
 
297
- if(node)
298
- {
299
- file = rb_str_new2(node->nd_file);
300
- line = INT2FIX(nd_line(node));
301
- }
330
+ file = rb_str_new2(node->nd_file);
331
+ line = INT2FIX(nd_line(node));
332
+
333
+ if(did_moved())
334
+ debug_context->moved = 1;
302
335
 
303
336
  switch(event)
304
337
  {
@@ -310,15 +343,15 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
310
343
  {
311
344
  rb_funcall(context, idAtTracing, 2, file, line);
312
345
  }
313
-
346
+
314
347
  if(debug_context->dest_frame == -1 ||
315
348
  RARRAY(debug_context->frames)->len == debug_context->dest_frame)
316
349
  {
317
350
  debug_context->stop_next--;
318
351
  if(debug_context->stop_next < 0)
319
- debug_context->stop_next = -1;
352
+ debug_context->stop_next = -1;
320
353
  /* we check that we actualy moved to another line */
321
- if(line != Qnil && debug_context->src_line != FIX2INT(line))
354
+ if(did_moved())
322
355
  {
323
356
  debug_context->stop_line--;
324
357
  }
@@ -334,7 +367,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
334
367
  }
335
368
 
336
369
  if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
337
- (breakpoint_index = check_breakpoints(context, file, klass, line)) != -1)
370
+ (breakpoint_index = check_breakpoints(debug_context, file, klass, line)) != -1)
338
371
  {
339
372
  binding = self? create_binding(self) : Qnil;
340
373
  /* check breakpoint expression */
@@ -342,41 +375,37 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
342
375
  {
343
376
  breakpoint = get_breakpoint_at(breakpoint_index);
344
377
  if(check_breakpoint_expression(breakpoint, binding))
345
- rb_funcall(context, idAtBreakpoint, 2, breakpoint, mid ? rb_str_new2(rb_id2name(mid)) : Qnil);
378
+ rb_funcall(context, idAtBreakpoint, 1, breakpoint);
346
379
  else
347
380
  break;
348
381
  }
349
382
 
350
383
  /* reset all pointers */
351
384
  debug_context->dest_frame = -1;
352
- debug_context->src_line = -1;
353
385
  debug_context->stop_line = -1;
354
386
  debug_context->stop_next = -1;
355
387
 
356
- call_debug_command(context, debug_context->thnum, binding, mid, file, line);
388
+ call_at_line(context, debug_context->thnum, binding, file, line);
357
389
  }
358
390
  break;
359
391
  }
360
392
  case RUBY_EVENT_C_CALL:
361
- {
362
- if(node)
363
393
  {
364
394
  set_frame_source(debug_context, file, line);
365
- }
366
- break;
395
+ break;
367
396
  }
368
397
  case RUBY_EVENT_CALL:
369
398
  {
370
399
  save_call_frame(self, file, line, mid, debug_context);
371
- breakpoint_index = check_breakpoints(context, file, klass, rb_str_new2(rb_id2name(mid)));
400
+ breakpoint_index = check_breakpoints(debug_context, file, klass, rb_str_new2(rb_id2name(mid)));
372
401
  if(breakpoint_index != -1)
373
402
  {
374
403
  binding = self? create_binding(self) : Qnil;
375
404
  breakpoint = get_breakpoint_at(breakpoint_index);
376
405
  if(check_breakpoint_expression(breakpoint, binding))
377
406
  {
378
- rb_funcall(context, idAtBreakpoint, 2, breakpoint, mid ? rb_str_new2(rb_id2name(mid)) : Qnil);
379
- call_debug_command(context, debug_context->thnum, binding, mid, file, line);
407
+ rb_funcall(context, idAtBreakpoint, 1, breakpoint);
408
+ call_at_line(context, debug_context->thnum, binding, file, line);
380
409
  }
381
410
  }
382
411
  break;
@@ -407,7 +436,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
407
436
  if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
408
437
  {
409
438
  debug_stop(mDebugger);
410
- rb_exit(0);
439
+ break;
411
440
  }
412
441
 
413
442
  if(catchpoint == Qnil)
@@ -419,10 +448,10 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
419
448
  aclass = rb_ary_entry(ancestors, i);
420
449
  if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
421
450
  {
422
- rb_funcall(context, idAtCatchpoint, 0);
451
+ rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
423
452
  binding = self? create_binding(self) : Qnil;
424
- call_debug_command(context, debug_context->thnum, binding, mid, file, line);
425
- break;
453
+ call_at_line(context, debug_context->thnum, binding, file, line);
454
+ break;
426
455
  }
427
456
  }
428
457
 
@@ -437,18 +466,6 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
437
466
  debugging--;
438
467
  }
439
468
 
440
- static VALUE
441
- debug_thnum(VALUE self)
442
- {
443
- VALUE thread, context;
444
- debug_context_t *debug_context;
445
-
446
- thread = rb_thread_current();
447
- context = thread_context_lookup(thread);
448
- Data_Get_Struct(context, debug_context_t, debug_context);
449
- return INT2FIX(debug_context->thnum);
450
- }
451
-
452
469
  static VALUE
453
470
  debug_start(VALUE self)
454
471
  {
@@ -743,9 +760,8 @@ context_stop_next(VALUE self, VALUE steps)
743
760
  static VALUE
744
761
  context_step_over(int argc, VALUE *argv, VALUE self)
745
762
  {
746
- VALUE lines, frame, cur_frame;
763
+ VALUE lines, frame;
747
764
  debug_context_t *debug_context;
748
- debug_frame_t *debug_frame;
749
765
 
750
766
  debug_check_started();
751
767
 
@@ -766,10 +782,6 @@ context_step_over(int argc, VALUE *argv, VALUE self)
766
782
  debug_context->dest_frame = FIX2INT(frame);
767
783
  }
768
784
 
769
- cur_frame = *RARRAY(debug_context->frames)->ptr;
770
- Data_Get_Struct(cur_frame, debug_frame_t, debug_frame);
771
- debug_context->src_line = FIX2INT(debug_frame->line);
772
-
773
785
  return Qnil;
774
786
  }
775
787
 
@@ -937,7 +949,6 @@ Init_ruby_debug()
937
949
  rb_define_module_function(mDebugger, "start", debug_start, 0);
938
950
  rb_define_module_function(mDebugger, "stop", debug_stop, 0);
939
951
  rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
940
- rb_define_module_function(mDebugger, "thnum", debug_thnum, 0);
941
952
  rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
942
953
  rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
943
954
  rb_define_module_function(mDebugger, "catchpoint", debug_catchpoint, 0);
@@ -974,7 +985,7 @@ Init_ruby_debug()
974
985
  rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
975
986
  rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
976
987
 
977
- idDebugCommand = rb_intern("debug_command");
988
+ idAtLine = rb_intern("at_line");
978
989
  idAtBreakpoint = rb_intern("at_breakpoint");
979
990
  idAtCatchpoint = rb_intern("at_catchpoint");
980
991
  idAtTracing = rb_intern("at_tracing");
@@ -0,0 +1,69 @@
1
+ module Debugger
2
+ class LocalInterface
3
+ def read_command(prompt)
4
+ readline(prompt, true)
5
+ end
6
+
7
+ def confirm(prompt)
8
+ readline(prompt, false)
9
+ end
10
+
11
+ def print(*args)
12
+ STDOUT.printf(*args)
13
+ end
14
+
15
+ def close
16
+ end
17
+
18
+ private
19
+
20
+ begin
21
+ require 'readline'
22
+ def readline(prompt, hist)
23
+ Readline::readline(prompt, hist)
24
+ end
25
+ rescue LoadError
26
+ def readline(prompt, hist)
27
+ STDOUT.print prompt
28
+ STDOUT.flush
29
+ line = STDIN.gets
30
+ exit unless line
31
+ line.chomp!
32
+ line
33
+ end
34
+ USE_READLINE = false
35
+ end
36
+ end
37
+
38
+ class RemoteInterface
39
+ def initialize(socket)
40
+ @socket = socket
41
+ end
42
+
43
+ def read_command(prompt)
44
+ send_command "PROMPT #{prompt}"
45
+ end
46
+
47
+ def confirm(prompt)
48
+ send_command "CONFIRM #{prompt}"
49
+ end
50
+
51
+ def print(*args)
52
+ @socket.printf(*args)
53
+ end
54
+
55
+ def close
56
+ @socket.close
57
+ rescue Exception
58
+ end
59
+
60
+ private
61
+
62
+ def send_command(msg)
63
+ @socket.puts msg
64
+ result = @socket.gets
65
+ raise IOError unless result
66
+ result.chomp
67
+ end
68
+ end
69
+ end