ruby-debug 0.1.5 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
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