ruby-debug-base 0.10.0-mswin32 → 0.10.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/ext/extconf.rb CHANGED
@@ -15,4 +15,6 @@ else
15
15
  exit(1)
16
16
  end
17
17
 
18
+ # Temporary: to turn off optimization
19
+ # $CFLAGS='-fno-strict-aliasing -g -fPIC'
18
20
  create_makefile("ruby_debug")
data/ext/ruby_debug.c CHANGED
@@ -1,11 +1,12 @@
1
+ #include "ruby_debug.h"
2
+
1
3
  #include <stdio.h>
2
- #include <ruby.h>
3
4
  #include <node.h>
4
5
  #include <rubysig.h>
5
6
  #include <st.h>
6
- #include <version.h>
7
+ #include <intern.h>
7
8
 
8
- #define DEBUG_VERSION "0.10.0"
9
+ #define DEBUG_VERSION "0.10.4"
9
10
 
10
11
  #ifdef _WIN32
11
12
  struct FRAME {
@@ -43,21 +44,6 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
43
44
  #include <env.h>
44
45
  #endif
45
46
 
46
- #define CTX_FL_SUSPEND (1<<1)
47
- #define CTX_FL_TRACING (1<<2)
48
- #define CTX_FL_SKIPPED (1<<3)
49
- #define CTX_FL_IGNORE (1<<4)
50
- #define CTX_FL_DEAD (1<<5)
51
- #define CTX_FL_WAS_RUNNING (1<<6)
52
- #define CTX_FL_ENABLE_BKPT (1<<7)
53
- #define CTX_FL_STEPPED (1<<8)
54
- #define CTX_FL_FORCE_MOVE (1<<9)
55
-
56
- #define CTX_FL_TEST(c,f) ((c)->flags & (f))
57
- #define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
58
- #define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
59
-
60
- #define IS_STARTED (threads_tbl != Qnil)
61
47
  #define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1])
62
48
  #define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
63
49
 
@@ -67,75 +53,10 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
67
53
 
68
54
  #define STACK_SIZE_INCREMENT 128
69
55
 
70
- typedef struct {
71
- int argc; /* Number of arguments a frame should have. */
72
- VALUE binding;
73
- ID id;
74
- ID orig_id;
75
- int line;
76
- const char * file;
77
- short dead;
78
- VALUE self;
79
- VALUE arg_ary;
80
- union {
81
- struct {
82
- struct FRAME *frame;
83
- struct SCOPE *scope;
84
- struct RVarmap *dyna_vars;
85
- } runtime;
86
- struct {
87
- VALUE args;
88
- VALUE locals;
89
- VALUE arg_ary;
90
- } copy;
91
- } info;
92
- } debug_frame_t;
93
-
94
- enum ctx_stop_reason {CTX_STOP_NONE, CTX_STOP_STEP, CTX_STOP_BREAKPOINT, CTX_STOP_CATCHPOINT};
95
-
96
- typedef struct {
97
- VALUE thread_id;
98
- int thnum;
99
- int flags;
100
- enum ctx_stop_reason stop_reason;
101
- int stop_next;
102
- int dest_frame;
103
- int stop_line;
104
- int stop_frame;
105
- int stack_size;
106
- int stack_len;
107
- debug_frame_t *frames;
108
- const char * last_file;
109
- int last_line;
110
- VALUE breakpoint;
111
- } debug_context_t;
112
-
113
- enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
114
- enum hit_condition {HIT_COND_NONE, HIT_COND_GE, HIT_COND_EQ, HIT_COND_MOD};
115
-
116
- typedef struct {
117
- int id;
118
- enum bp_type type;
119
- VALUE source;
120
- union
121
- {
122
- int line;
123
- ID mid;
124
- } pos;
125
- VALUE expr;
126
- VALUE enabled;
127
- int hit_count;
128
- int hit_value;
129
- enum hit_condition hit_condition;
130
- } debug_breakpoint_t;
131
-
132
56
  typedef struct {
133
57
  st_table *tbl;
134
58
  } threads_table_t;
135
59
 
136
- static VALUE threads_tbl = Qnil;
137
- static VALUE breakpoints = Qnil;
138
- static VALUE catchpoint = Qnil;
139
60
  static VALUE tracing = Qfalse;
140
61
  static VALUE locker = Qnil;
141
62
  static VALUE post_mortem = Qfalse;
@@ -147,20 +68,21 @@ static VALUE last_context = Qnil;
147
68
  static VALUE last_thread = Qnil;
148
69
  static debug_context_t *last_debug_context = NULL;
149
70
 
150
- static VALUE mDebugger;
71
+ VALUE rdebug_threads_tbl = Qnil; /* Context for each of the threads */
72
+ VALUE mDebugger; /* Ruby Debugger Module object */
73
+
151
74
  static VALUE cThreadsTable;
152
75
  static VALUE cContext;
153
- static VALUE cBreakpoint;
154
76
  static VALUE cDebugThread;
155
77
 
156
78
  static VALUE rb_mObjectSpace;
157
79
 
158
- static ID idAtLine;
159
80
  static ID idAtBreakpoint;
160
81
  static ID idAtCatchpoint;
82
+ static ID idAtLine;
83
+ static ID idAtReturn;
161
84
  static ID idAtTracing;
162
85
  static ID idList;
163
- static ID idEval;
164
86
 
165
87
  static int start_count = 0;
166
88
  static int thnum_max = 0;
@@ -186,6 +108,17 @@ typedef struct locked_thread_t {
186
108
  static locked_thread_t *locked_head = NULL;
187
109
  static locked_thread_t *locked_tail = NULL;
188
110
 
111
+ /* "Step", "Next" and "Finish" do their work by saving information
112
+ about where to stop next. reset_stopping_points removes/resets this
113
+ information. */
114
+ inline static void
115
+ reset_stepping_stop_points(debug_context_t *debug_context)
116
+ {
117
+ debug_context->dest_frame = -1;
118
+ debug_context->stop_line = -1;
119
+ debug_context->stop_next = -1;
120
+ }
121
+
189
122
  inline static VALUE
190
123
  real_class(VALUE klass)
191
124
  {
@@ -379,7 +312,7 @@ check_thread_contexts()
379
312
  {
380
313
  threads_table_t *threads_table;
381
314
 
382
- Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
315
+ Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
383
316
  st_foreach(threads_table->tbl, threads_table_check_i, 0);
384
317
  }
385
318
 
@@ -395,15 +328,6 @@ debug_is_started(VALUE self)
395
328
  return IS_STARTED ? Qtrue : Qfalse;
396
329
  }
397
330
 
398
- static void
399
- debug_check_started()
400
- {
401
- if(!IS_STARTED)
402
- {
403
- rb_raise(rb_eRuntimeError, "Debugger.start is not called yet.");
404
- }
405
- }
406
-
407
331
  static void
408
332
  debug_context_mark(void *data)
409
333
  {
@@ -416,6 +340,7 @@ debug_context_mark(void *data)
416
340
  frame = &(debug_context->frames[i]);
417
341
  rb_gc_mark(frame->binding);
418
342
  rb_gc_mark(frame->self);
343
+ rb_gc_mark(frame->arg_ary);
419
344
  if(frame->dead)
420
345
  {
421
346
  rb_gc_mark(frame->info.copy.locals);
@@ -505,7 +430,7 @@ thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_cont
505
430
  return;
506
431
  }
507
432
  thread_id = ref2id(thread);
508
- Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
433
+ Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
509
434
  if(!st_lookup(threads_table->tbl, thread_id, context))
510
435
  {
511
436
  *context = debug_context_create(thread);
@@ -554,7 +479,7 @@ save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debu
554
479
  if(frame_n >= debug_context->stack_len)
555
480
  {
556
481
  debug_context->stack_len += STACK_SIZE_INCREMENT;
557
- debug_context->frames = REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len);
482
+ REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len);
558
483
  }
559
484
  debug_frame = &debug_context->frames[frame_n];
560
485
  debug_frame->argc = ruby_frame->argc;
@@ -565,6 +490,7 @@ save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debu
565
490
  debug_frame->orig_id = mid;
566
491
  debug_frame->dead = 0;
567
492
  debug_frame->self = self;
493
+ debug_frame->arg_ary = Qnil;
568
494
  debug_frame->info.runtime.frame = ruby_frame;
569
495
  debug_frame->info.runtime.scope = ruby_scope;
570
496
  debug_frame->info.runtime.dyna_vars = event == RUBY_EVENT_LINE ? ruby_dyna_vars : NULL;
@@ -579,7 +505,7 @@ save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debu
579
505
  #define isdirsep(x) ((x) == '/')
580
506
  #endif
581
507
 
582
- static int
508
+ int
583
509
  filename_cmp(VALUE source, char *file)
584
510
  {
585
511
  char *source_ptr, *file_ptr;
@@ -606,136 +532,10 @@ filename_cmp(VALUE source, char *file)
606
532
  return 1;
607
533
  }
608
534
 
609
- inline static int
610
- classname_cmp(VALUE name, VALUE klass)
611
- {
612
- VALUE class_name = (Qnil == name) ? rb_str_new2("main") : name;
613
- return (klass != Qnil
614
- && rb_str_cmp(class_name, rb_mod_name(klass)) == 0);
615
- }
616
-
617
- static int
618
- check_breakpoint_hit_condition(VALUE breakpoint)
619
- {
620
- debug_breakpoint_t *debug_breakpoint;
621
-
622
- if(breakpoint == Qnil)
623
- return 0;
624
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
625
-
626
- debug_breakpoint->hit_count++;
627
- if (!Qtrue == debug_breakpoint->enabled) return 0;
628
- switch(debug_breakpoint->hit_condition)
629
- {
630
- case HIT_COND_NONE:
631
- return 1;
632
- case HIT_COND_GE:
633
- {
634
- if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value)
635
- return 1;
636
- break;
637
- }
638
- case HIT_COND_EQ:
639
- {
640
- if(debug_breakpoint->hit_count == debug_breakpoint->hit_value)
641
- return 1;
642
- break;
643
- }
644
- case HIT_COND_MOD:
645
- {
646
- if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0)
647
- return 1;
648
- break;
649
- }
650
- }
651
- return 0;
652
- }
653
-
654
- static int
655
- check_breakpoint_by_pos(VALUE breakpoint, char *file, int line)
656
- {
657
- debug_breakpoint_t *debug_breakpoint;
658
-
659
- if(breakpoint == Qnil)
660
- return 0;
661
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
662
- if (!Qtrue == debug_breakpoint->enabled) return 0;
663
- if(debug_breakpoint->type != BP_POS_TYPE)
664
- return 0;
665
- if(debug_breakpoint->pos.line != line)
666
- return 0;
667
- if(filename_cmp(debug_breakpoint->source, file))
668
- return 1;
669
- return 0;
670
- }
671
-
672
- static int
673
- check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid)
674
- {
675
- debug_breakpoint_t *debug_breakpoint;
676
-
677
- if(breakpoint == Qnil)
678
- return 0;
679
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
680
- if (!Qtrue == debug_breakpoint->enabled) return 0;
681
- if(debug_breakpoint->type != BP_METHOD_TYPE)
682
- return 0;
683
- if(debug_breakpoint->pos.mid != mid)
684
- return 0;
685
- if(classname_cmp(debug_breakpoint->source, klass))
686
- return 1;
687
- return 0;
688
- }
689
-
690
- static VALUE
691
- check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
692
- {
693
- VALUE breakpoint;
694
- int i;
695
-
696
- if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
697
- return Qnil;
698
-
699
- if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
700
- return debug_context->breakpoint;
701
-
702
- if(RARRAY(breakpoints)->len == 0)
703
- return Qnil;
704
- for(i = 0; i < RARRAY(breakpoints)->len; i++)
705
- {
706
- breakpoint = rb_ary_entry(breakpoints, i);
707
- if(check_breakpoint_by_pos(breakpoint, file, line))
708
- return breakpoint;
709
- }
710
- return Qnil;
711
- }
712
-
713
- static VALUE
714
- check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid)
715
- {
716
- VALUE breakpoint;
717
- int i;
718
-
719
- if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
720
- return Qnil;
721
-
722
- if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid))
723
- return debug_context->breakpoint;
724
-
725
- if(RARRAY(breakpoints)->len == 0)
726
- return Qnil;
727
- for(i = 0; i < RARRAY(breakpoints)->len; i++)
728
- {
729
- breakpoint = rb_ary_entry(breakpoints, i);
730
- if(check_breakpoint_by_method(breakpoint, klass, mid))
731
- return breakpoint;
732
- }
733
- return Qnil;
734
- }
735
-
736
535
  /*
737
- * This is a NASTY HACK. For some reasons rb_f_binding is declared
738
- * static in eval.c. So we create a cons up call to binding in C.
536
+ * A nasty hack to be able to get at the +Kernel.binding+ method.
537
+ * +rb_f_binding+ is declared static in eval.c. So copy and save our own value
538
+ * of it by looking up the method name in the Kernel module.
739
539
  */
740
540
  static VALUE
741
541
  create_binding(VALUE self)
@@ -750,27 +550,6 @@ create_binding(VALUE self)
750
550
  return f_binding(self);
751
551
  }
752
552
 
753
- static VALUE
754
- eval_expression(VALUE args)
755
- {
756
- return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr);
757
- }
758
-
759
- inline static int
760
- check_breakpoint_expression(VALUE breakpoint, VALUE binding)
761
- {
762
- debug_breakpoint_t *debug_breakpoint;
763
- VALUE args, expr_result;
764
-
765
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
766
- if(NIL_P(debug_breakpoint->expr))
767
- return 1;
768
-
769
- args = rb_ary_new3(2, debug_breakpoint->expr, binding);
770
- expr_result = rb_protect(eval_expression, args, 0);
771
- return RTEST(expr_result);
772
- }
773
-
774
553
  inline static debug_frame_t *
775
554
  get_top_frame(debug_context_t *debug_context)
776
555
  {
@@ -921,11 +700,31 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
921
700
  if(debug == Qtrue)
922
701
  fprintf(stderr, "%s:%d [%s] %s\n", file, line, get_event_name(event), rb_id2name(mid));
923
702
 
703
+ /* There can be many event calls per line, but we only want
704
+ *one* breakpoint per line. */
924
705
  if(debug_context->last_line != line || debug_context->last_file == NULL ||
925
706
  strcmp(debug_context->last_file, file) != 0)
926
707
  {
927
708
  CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT);
928
709
  moved = 1;
710
+ }
711
+ else if(event == RUBY_EVENT_LINE)
712
+ {
713
+ /* There are two line-event trace hook calls per IF node - one
714
+ before the expression eval an done afterwards.
715
+ */
716
+ /* FIXME: the static variable can't be safely used here, since this method
717
+ is re-entrant by multiple threads. If we want to provide this kind of functionality
718
+ if_eval_event variable must be moved to debug_context structure.
719
+ */
720
+ /*
721
+ static int if_eval_event = 0;
722
+ if_eval_event = (NODE_IF == nd_type(node)) ? !if_eval_event : 0;
723
+ if (!if_eval_event)
724
+ {
725
+ CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT);
726
+ }
727
+ */
929
728
  }
930
729
  }
931
730
  else if(event != RUBY_EVENT_RETURN && event != RUBY_EVENT_C_RETURN)
@@ -999,11 +798,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
999
798
  debug_context->breakpoint = Qnil;
1000
799
  }
1001
800
 
1002
- /* reset all pointers */
1003
- debug_context->dest_frame = -1;
1004
- debug_context->stop_line = -1;
1005
- debug_context->stop_next = -1;
1006
-
801
+ reset_stepping_stop_points(debug_context);
1007
802
  call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
1008
803
  }
1009
804
  break;
@@ -1011,7 +806,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
1011
806
  case RUBY_EVENT_CALL:
1012
807
  {
1013
808
  save_call_frame(event, self, file, line, mid, debug_context);
1014
- breakpoint = check_breakpoints_by_method(debug_context, klass, mid);
809
+ breakpoint = check_breakpoints_by_method(debug_context, klass, mid, self);
1015
810
  if(breakpoint != Qnil)
1016
811
  {
1017
812
  debug_frame_t *debug_frame;
@@ -1058,6 +853,9 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
1058
853
  {
1059
854
  debug_context->stop_next = 1;
1060
855
  debug_context->stop_frame = 0;
856
+ /* NOTE: can't use call_at_line function here to trigger a debugger event.
857
+ this can lead to segfault. We should only unroll the stack on this event.
858
+ */
1061
859
  }
1062
860
  while(debug_context->stack_size > 0)
1063
861
  {
@@ -1092,21 +890,48 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
1092
890
  }
1093
891
 
1094
892
  expn_class = rb_obj_class(ruby_errinfo);
893
+
894
+ /* This code goes back to the earliest days of ruby-debug. It
895
+ tends to disallow catching an exception via the
896
+ "catchpoint" command. To address this one possiblilty is to
897
+ move this after testing for catchponts. Kent however thinks
898
+ there may be a misfeature in Ruby's eval.c: the problem was
899
+ in the fact that Ruby doesn't reset exception flag on the
900
+ current thread before it calls a notification handler.
901
+
902
+ See also the #ifdef'd code below as well.
903
+ */
904
+ #ifdef NORMAL_CODE
1095
905
  if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
1096
906
  {
1097
907
  debug_stop(mDebugger);
1098
908
  break;
1099
909
  }
910
+ #endif
1100
911
 
1101
- if(catchpoint == Qnil)
912
+ if (rdebug_catchpoints == Qnil ||
913
+ RHASH(rdebug_catchpoints)->tbl->num_entries == 0)
1102
914
  break;
1103
915
 
1104
916
  ancestors = rb_mod_ancestors(expn_class);
1105
917
  for(i = 0; i < RARRAY(ancestors)->len; i++)
1106
918
  {
1107
- aclass = rb_ary_entry(ancestors, i);
1108
- if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
919
+ VALUE mod_name;
920
+ VALUE hit_count;
921
+
922
+ aclass = rb_ary_entry(ancestors, i);
923
+ mod_name = rb_mod_name(aclass);
924
+ hit_count = rb_hash_aref(rdebug_catchpoints, mod_name);
925
+ if(hit_count != Qnil)
1109
926
  {
927
+ /* On 64-bit systems with gcc and -O2 there seems to be
928
+ an optimization bug in running INT2FIX(FIX2INT...)..)
929
+ So we do this in two steps.
930
+ */
931
+ int c_hit_count = FIX2INT(rb_hash_aref(rdebug_catchpoints,
932
+ mod_name)) + 1;
933
+ hit_count = INT2FIX(c_hit_count);
934
+ rb_hash_aset(rdebug_catchpoints, mod_name, hit_count);
1110
935
  debug_context->stop_reason = CTX_STOP_CATCHPOINT;
1111
936
  rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
1112
937
  if(self && binding == Qnil)
@@ -1117,6 +942,18 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
1117
942
  }
1118
943
  }
1119
944
 
945
+ /* If we stop the debugger, we may not be able to trace into
946
+ code that has an exception handler wrapped around it. So
947
+ the alternative is to force the user to do his own
948
+ Debugger.stop. */
949
+ #ifdef NORMAL_CODE_MOVING_AFTER_
950
+ if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
951
+ {
952
+ debug_stop(mDebugger);
953
+ break;
954
+ }
955
+ #endif
956
+
1120
957
  break;
1121
958
  }
1122
959
  }
@@ -1150,16 +987,29 @@ debug_stop_i(VALUE self)
1150
987
 
1151
988
  /*
1152
989
  * call-seq:
1153
- * Debugger.start -> bool
1154
- * Debugger.start { ... } -> obj
990
+ * Debugger.start_ -> bool
991
+ * Debugger.start_ { ... } -> bool
1155
992
  *
1156
- * This method activates the debugger.
1157
- * If it's called without a block it returns +true+, unless debugger was already started.
1158
- * If a block is given, it starts debugger and yields to block. When the block is finished
1159
- * executing it stops the debugger with Debugger.stop method.
993
+ * This method is internal and activates the debugger. Use
994
+ * Debugger.start (from <tt>lib/ruby-debug-base.rb</tt>) instead.
995
+ *
996
+ * The return value is the value of !Debugger.started? <i>before</i>
997
+ * issuing the +start+; That is, +true+ is returned, unless debugger
998
+ * was previously started.
999
+
1000
+ * If a block is given, it starts debugger and yields to block. When
1001
+ * the block is finished executing it stops the debugger with
1002
+ * Debugger.stop method. Inside the block you will probably want to
1003
+ * have a call to Debugger.debugger. For example:
1004
+ * Debugger.start{debugger; foo} # Stop inside of foo
1005
+ *
1006
+ * Also, ruby-debug only allows
1007
+ * one invocation of debugger at a time; nested Debugger.start's
1008
+ * have no effect and you can't use this inside the debugger itself.
1160
1009
  *
1161
- * <i>Note that if you want to stop debugger, you must call Debugger.stop as many time as you
1162
- * called Debugger.start method.</i>
1010
+ * <i>Note that if you want to completely remove the debugger hook,
1011
+ * you must call Debugger.stop as many times as you called
1012
+ * Debugger.start method.</i>
1163
1013
  */
1164
1014
  static VALUE
1165
1015
  debug_start(VALUE self)
@@ -1171,16 +1021,18 @@ debug_start(VALUE self)
1171
1021
  result = Qfalse;
1172
1022
  else
1173
1023
  {
1174
- breakpoints = rb_ary_new();
1175
- locker = Qnil;
1176
- threads_tbl = threads_table_create();
1024
+ locker = Qnil;
1025
+ rdebug_breakpoints = rb_ary_new();
1026
+ rdebug_catchpoints = rb_hash_new();
1027
+ rdebug_threads_tbl = threads_table_create();
1177
1028
 
1178
1029
  rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL);
1179
1030
  result = Qtrue;
1180
1031
  }
1181
1032
 
1182
- if(rb_block_given_p())
1183
- return rb_ensure(rb_yield, self, debug_stop_i, self);
1033
+ if(rb_block_given_p())
1034
+ rb_ensure(rb_yield, self, debug_stop_i, self);
1035
+
1184
1036
  return result;
1185
1037
  }
1186
1038
 
@@ -1191,9 +1043,9 @@ debug_start(VALUE self)
1191
1043
  * This method disables the debugger. It returns +true+ if the debugger is disabled,
1192
1044
  * otherwise it returns +false+.
1193
1045
  *
1194
- * <i>Note that if you want to stop debugger, you must call
1195
- * Debugger.stop as many times as you called Debugger.start
1196
- * method.</i>
1046
+ * <i>Note that if you want to complete remove the debugger hook,
1047
+ * you must call Debugger.stop as many times as you called
1048
+ * Debugger.start method.</i>
1197
1049
  */
1198
1050
  static VALUE
1199
1051
  debug_stop(VALUE self)
@@ -1206,156 +1058,13 @@ debug_stop(VALUE self)
1206
1058
 
1207
1059
  rb_remove_event_hook(debug_event_hook);
1208
1060
 
1209
- locker = Qnil;
1210
- breakpoints = Qnil;
1211
- threads_tbl = Qnil;
1061
+ locker = Qnil;
1062
+ rdebug_breakpoints = Qnil;
1063
+ rdebug_threads_tbl = Qnil;
1212
1064
 
1213
1065
  return Qtrue;
1214
1066
  }
1215
1067
 
1216
- static void
1217
- breakpoint_mark(void *data)
1218
- {
1219
- debug_breakpoint_t *breakpoint;
1220
- breakpoint = (debug_breakpoint_t *)data;
1221
- rb_gc_mark(breakpoint->source);
1222
- rb_gc_mark(breakpoint->expr);
1223
- }
1224
-
1225
- static VALUE
1226
- create_breakpoint_from_args(int argc, VALUE *argv, int id)
1227
- {
1228
- VALUE source, pos, expr;
1229
- debug_breakpoint_t *breakpoint;
1230
- int type;
1231
-
1232
- if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
1233
- {
1234
- expr = Qnil;
1235
- }
1236
- type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
1237
- if(type == BP_POS_TYPE)
1238
- source = StringValue(source);
1239
- else
1240
- pos = StringValue(pos);
1241
- breakpoint = ALLOC(debug_breakpoint_t);
1242
- breakpoint->id = id;
1243
- breakpoint->source = source;
1244
- breakpoint->type = type;
1245
- if(type == BP_POS_TYPE)
1246
- breakpoint->pos.line = FIX2INT(pos);
1247
- else
1248
- breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr);
1249
- breakpoint->enabled = Qtrue;
1250
- breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
1251
- breakpoint->hit_count = 0;
1252
- breakpoint->hit_value = 0;
1253
- breakpoint->hit_condition = HIT_COND_NONE;
1254
- return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
1255
- }
1256
-
1257
- /*
1258
- * call-seq:
1259
- * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
1260
- *
1261
- * Adds a new breakpoint.
1262
- * <i>source</i> is a name of a file or a class.
1263
- * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
1264
- * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
1265
- * is activated.
1266
- */
1267
- static VALUE
1268
- debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
1269
- {
1270
- VALUE result;
1271
-
1272
- debug_check_started();
1273
-
1274
- result = create_breakpoint_from_args(argc, argv, ++bkp_count);
1275
- rb_ary_push(breakpoints, result);
1276
- return result;
1277
- }
1278
-
1279
- /*
1280
- * call-seq:
1281
- * Debugger.remove_breakpoint(id) -> breakpoint
1282
- *
1283
- * Removes breakpoint by its id.
1284
- * <i>id</i> is an identificator of a breakpoint.
1285
- */
1286
- static VALUE
1287
- debug_remove_breakpoint(VALUE self, VALUE id_value)
1288
- {
1289
- int i;
1290
- int id;
1291
- VALUE breakpoint;
1292
- debug_breakpoint_t *debug_breakpoint;
1293
-
1294
- id = FIX2INT(id_value);
1295
-
1296
- for( i = 0; i < RARRAY(breakpoints)->len; i += 1 )
1297
- {
1298
- breakpoint = rb_ary_entry(breakpoints, i);
1299
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
1300
- if(debug_breakpoint->id == id)
1301
- {
1302
- rb_ary_delete_at(breakpoints, i);
1303
- return breakpoint;
1304
- }
1305
- }
1306
- return Qnil;
1307
- }
1308
-
1309
- /*
1310
- * call-seq:
1311
- * Debugger.breakpoints -> array
1312
- *
1313
- * Returns an array of breakpoints.
1314
- */
1315
- static VALUE
1316
- debug_breakpoints(VALUE self)
1317
- {
1318
- debug_check_started();
1319
-
1320
- return breakpoints;
1321
- }
1322
-
1323
- /*
1324
- * call-seq:
1325
- * Debugger.checkpoint -> string
1326
- *
1327
- * Returns a current checkpoint, which is a name of exception that will
1328
- * trigger a debugger when raised.
1329
- */
1330
- static VALUE
1331
- debug_catchpoint(VALUE self)
1332
- {
1333
- debug_check_started();
1334
-
1335
- return catchpoint;
1336
- }
1337
-
1338
- /*
1339
- * call-seq:
1340
- * Debugger.checkpoint = string -> string
1341
- *
1342
- * Sets checkpoint.
1343
- */
1344
- static VALUE
1345
- debug_set_catchpoint(VALUE self, VALUE value)
1346
- {
1347
- debug_check_started();
1348
-
1349
- if (!NIL_P(value) && TYPE(value) != T_STRING) {
1350
- rb_raise(rb_eTypeError, "value of checkpoint must be String");
1351
- }
1352
- if(NIL_P(value))
1353
- catchpoint = Qnil;
1354
- else
1355
- catchpoint = rb_str_dup(value);
1356
- return value;
1357
- }
1358
-
1359
1068
  static int
1360
1069
  find_last_context_func(VALUE key, VALUE value, VALUE *result)
1361
1070
  {
@@ -1383,7 +1092,7 @@ debug_last_interrupted(VALUE self)
1383
1092
 
1384
1093
  debug_check_started();
1385
1094
 
1386
- Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
1095
+ Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
1387
1096
 
1388
1097
  st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result);
1389
1098
  return result;
@@ -1451,8 +1160,8 @@ debug_contexts(VALUE self)
1451
1160
  thread_context_lookup(thread, &context, NULL);
1452
1161
  rb_ary_push(new_list, context);
1453
1162
  }
1454
- threads_table_clear(threads_tbl);
1455
- Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
1163
+ threads_table_clear(rdebug_threads_tbl);
1164
+ Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
1456
1165
  for(i = 0; i < RARRAY(new_list)->len; i++)
1457
1166
  {
1458
1167
  context = rb_ary_entry(new_list, i);
@@ -1665,30 +1374,57 @@ debug_thread_inherited(VALUE klass)
1665
1374
 
1666
1375
  /*
1667
1376
  * call-seq:
1668
- * Debugger.debug_load(file, stop = false) -> nil
1377
+ * Debugger.debug_load(file, stop = false, increment_start = false) -> nil
1669
1378
  *
1670
1379
  * Same as Kernel#load but resets current context's frames.
1671
- * +stop+ parameter force the debugger to stop at the first line of code in the +file+
1380
+ * +stop+ parameter forces the debugger to stop at the first line of code in the +file+
1381
+ * +increment_start+ determines if start_count should be incremented. When
1382
+ * control threads are used, they have to be set up before loading the
1383
+ * debugger; so here +increment_start+ will be false.
1672
1384
  * FOR INTERNAL USE ONLY.
1673
1385
  */
1674
1386
  static VALUE
1675
1387
  debug_debug_load(int argc, VALUE *argv, VALUE self)
1676
1388
  {
1677
- VALUE file, stop, context;
1389
+ VALUE file, stop, context, increment_start;
1678
1390
  debug_context_t *debug_context;
1679
-
1680
- if(rb_scan_args(argc, argv, "11", &file, &stop) == 1)
1681
- stop = Qfalse;
1391
+ int state = 0;
1392
+
1393
+ if(rb_scan_args(argc, argv, "12", &file, &stop, &increment_start) == 1)
1394
+ {
1395
+ stop = Qfalse;
1396
+ increment_start = Qtrue;
1397
+ }
1682
1398
 
1683
1399
  debug_start(self);
1400
+ if (Qfalse == increment_start) start_count--;
1401
+
1684
1402
  context = debug_current_context(self);
1685
1403
  Data_Get_Struct(context, debug_context_t, debug_context);
1686
1404
  debug_context->stack_size = 0;
1687
1405
  if(RTEST(stop))
1688
1406
  debug_context->stop_next = 1;
1689
- rb_load(file, 0);
1407
+ /* Initializing $0 to the script's path */
1408
+ ruby_script(RSTRING(file)->ptr);
1409
+ rb_load_protect(file, 0, &state);
1410
+ if (0 != state) {
1411
+ VALUE errinfo = ruby_errinfo;
1412
+ debug_suspend(self);
1413
+ reset_stepping_stop_points(debug_context);
1414
+ ruby_errinfo = Qnil;
1415
+ return errinfo;
1416
+ }
1417
+
1418
+ /* We should run all at_exit handler's in order to provide,
1419
+ * for instance, a chance to run all defined test cases */
1420
+ rb_exec_end_proc();
1421
+
1422
+ /* We could have issued a Debugger.stop inside the debug
1423
+ session. */
1424
+ if (start_count > 0) {
1425
+ debug_stop(self);
1426
+ }
1690
1427
 
1691
- debug_stop(self);
1692
1428
  return Qnil;
1693
1429
  }
1694
1430
 
@@ -1836,7 +1572,7 @@ context_step_over(int argc, VALUE *argv, VALUE self)
1836
1572
  * call-seq:
1837
1573
  * context.stop_frame(frame)
1838
1574
  *
1839
- * Stops when a frame with number +frame+ is activated. Implements +up+ and +down+ commands.
1575
+ * Stops when a frame with number +frame+ is activated. Implements +finish+ and +next+ commands.
1840
1576
  */
1841
1577
  static VALUE
1842
1578
  context_stop_frame(VALUE self, VALUE frame)
@@ -2341,7 +2077,7 @@ context_tracing(VALUE self)
2341
2077
 
2342
2078
  /*
2343
2079
  * call-seq:
2344
- * context.tracking = bool
2080
+ * context.tracing = bool
2345
2081
  *
2346
2082
  * Controls the tracing for this context.
2347
2083
  */
@@ -2395,50 +2131,6 @@ context_dead(VALUE self)
2395
2131
  return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse;
2396
2132
  }
2397
2133
 
2398
- /*
2399
- * call-seq:
2400
- * context.breakpoint -> breakpoint
2401
- *
2402
- * Returns a context-specific temporary Breakpoint object.
2403
- */
2404
- static VALUE
2405
- context_breakpoint(VALUE self)
2406
- {
2407
- debug_context_t *debug_context;
2408
-
2409
- debug_check_started();
2410
-
2411
- Data_Get_Struct(self, debug_context_t, debug_context);
2412
- return debug_context->breakpoint;
2413
- }
2414
-
2415
- /*
2416
- * call-seq:
2417
- * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
2418
- *
2419
- * Sets a context-specific temporary breakpoint, which can be used to implement
2420
- * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
2421
- * cleared out.
2422
- *
2423
- * <i>source</i> is a name of a file or a class.
2424
- * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
2425
- * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
2426
- * is activated.
2427
- */
2428
- static VALUE
2429
- context_set_breakpoint(int argc, VALUE *argv, VALUE self)
2430
- {
2431
- VALUE result;
2432
- debug_context_t *debug_context;
2433
-
2434
- debug_check_started();
2435
-
2436
- Data_Get_Struct(self, debug_context_t, debug_context);
2437
- result = create_breakpoint_from_args(argc, argv, 0);
2438
- debug_context->breakpoint = result;
2439
- return result;
2440
- }
2441
-
2442
2134
  /*
2443
2135
  * call-seq:
2444
2136
  * context.stop_reason -> sym
@@ -2478,262 +2170,13 @@ context_stop_reason(VALUE self)
2478
2170
  }
2479
2171
 
2480
2172
 
2481
- /*
2482
- * call-seq:
2483
- * breakpoint.enabled?
2484
- *
2485
- * Returns whether breakpoint is enabled or not.
2486
- */
2487
- static VALUE
2488
- breakpoint_enabled(VALUE self)
2489
- {
2490
- debug_breakpoint_t *breakpoint;
2491
-
2492
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2493
- return breakpoint->enabled;
2494
- }
2495
-
2496
- /*
2497
- * call-seq:
2498
- * breakpoint.enabled = bool
2499
- *
2500
- * Enables or disables breakpoint.
2501
- */
2502
- static VALUE
2503
- breakpoint_set_enabled(VALUE self, VALUE bool)
2504
- {
2505
- debug_breakpoint_t *breakpoint;
2506
-
2507
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2508
- return breakpoint->enabled = bool;
2509
- }
2510
-
2511
- /*
2512
- * call-seq:
2513
- * breakpoint.source -> string
2514
- *
2515
- * Returns a source of the breakpoint.
2516
- */
2517
- static VALUE
2518
- breakpoint_source(VALUE self)
2519
- {
2520
- debug_breakpoint_t *breakpoint;
2521
-
2522
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2523
- return breakpoint->source;
2524
- }
2525
-
2526
- /*
2527
- * call-seq:
2528
- * breakpoint.source = string
2529
- *
2530
- * Sets the source of the breakpoint.
2531
- */
2532
- static VALUE
2533
- breakpoint_set_source(VALUE self, VALUE value)
2534
- {
2535
- debug_breakpoint_t *breakpoint;
2536
-
2537
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2538
- breakpoint->source = StringValue(value);
2539
- return value;
2540
- }
2541
-
2542
- /*
2543
- * call-seq:
2544
- * breakpoint.pos -> string or int
2545
- *
2546
- * Returns a position of this breakpoint.
2547
- */
2548
- static VALUE
2549
- breakpoint_pos(VALUE self)
2550
- {
2551
- debug_breakpoint_t *breakpoint;
2552
-
2553
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2554
- if(breakpoint->type == BP_METHOD_TYPE)
2555
- return rb_str_new2(rb_id2name(breakpoint->pos.mid));
2556
- else
2557
- return INT2FIX(breakpoint->pos.line);
2558
- }
2559
-
2560
- /*
2561
- * call-seq:
2562
- * breakpoint.pos = string or int
2563
- *
2564
- * Sets the position of this breakpoint.
2565
- */
2566
- static VALUE
2567
- breakpoint_set_pos(VALUE self, VALUE value)
2568
- {
2569
- debug_breakpoint_t *breakpoint;
2570
-
2571
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2572
- if(breakpoint->type == BP_METHOD_TYPE)
2573
- {
2574
- breakpoint->pos.mid = rb_to_id(StringValue(value));
2575
- }
2576
- else
2577
- breakpoint->pos.line = FIX2INT(value);
2578
- return value;
2579
- }
2580
-
2581
- /*
2582
- * call-seq:
2583
- * breakpoint.expr -> string
2584
- *
2585
- * Returns a codition expression when this breakpoint should be activated.
2586
- */
2587
- static VALUE
2588
- breakpoint_expr(VALUE self)
2589
- {
2590
- debug_breakpoint_t *breakpoint;
2591
-
2592
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2593
- return breakpoint->expr;
2594
- }
2595
-
2596
- /*
2597
- * call-seq:
2598
- * breakpoint.expr = string
2599
- *
2600
- * Sets the codition expression when this breakpoint should be activated.
2601
- */
2602
- static VALUE
2603
- breakpoint_set_expr(VALUE self, VALUE value)
2604
- {
2605
- debug_breakpoint_t *breakpoint;
2606
-
2607
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2608
- breakpoint->expr = StringValue(value);
2609
- return value;
2610
- }
2611
-
2612
- /*
2613
- * call-seq:
2614
- * breakpoint.id -> int
2615
- *
2616
- * Returns id of the breakpoint.
2617
- */
2618
- static VALUE
2619
- breakpoint_id(VALUE self)
2620
- {
2621
- debug_breakpoint_t *breakpoint;
2622
-
2623
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2624
- return INT2FIX(breakpoint->id);
2625
- }
2626
-
2627
- /*
2628
- * call-seq:
2629
- * breakpoint.hit_count -> int
2630
- *
2631
- * Returns the hit count of the breakpoint.
2632
- */
2633
- static VALUE
2634
- breakpoint_hit_count(VALUE self)
2635
- {
2636
- debug_breakpoint_t *breakpoint;
2637
-
2638
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2639
- return INT2FIX(breakpoint->hit_count);
2640
- }
2641
-
2642
- /*
2643
- * call-seq:
2644
- * breakpoint.hit_value -> int
2645
- *
2646
- * Returns the hit value of the breakpoint.
2647
- */
2648
- static VALUE
2649
- breakpoint_hit_value(VALUE self)
2650
- {
2651
- debug_breakpoint_t *breakpoint;
2652
-
2653
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2654
- return INT2FIX(breakpoint->hit_value);
2655
- }
2656
-
2657
- /*
2658
- * call-seq:
2659
- * breakpoint.hit_value = int
2660
- *
2661
- * Sets the hit value of the breakpoint.
2662
- */
2663
- static VALUE
2664
- breakpoint_set_hit_value(VALUE self, VALUE value)
2665
- {
2666
- debug_breakpoint_t *breakpoint;
2667
-
2668
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2669
- breakpoint->hit_value = FIX2INT(value);
2670
- return value;
2671
- }
2672
-
2673
- /*
2674
- * call-seq:
2675
- * breakpoint.hit_condition -> symbol
2676
- *
2677
- * Returns the hit condition of the breakpoint:
2678
- *
2679
- * +nil+ if it is an unconditional breakpoint, or
2680
- * :greater_or_equal, :equal, :modulo
2681
- */
2682
- static VALUE
2683
- breakpoint_hit_condition(VALUE self)
2684
- {
2685
- debug_breakpoint_t *breakpoint;
2686
-
2687
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2688
- switch(breakpoint->hit_condition)
2689
- {
2690
- case HIT_COND_GE:
2691
- return ID2SYM(rb_intern("greater_or_equal"));
2692
- case HIT_COND_EQ:
2693
- return ID2SYM(rb_intern("equal"));
2694
- case HIT_COND_MOD:
2695
- return ID2SYM(rb_intern("modulo"));
2696
- case HIT_COND_NONE:
2697
- default:
2698
- return Qnil;
2699
- }
2700
- }
2701
-
2702
- /*
2703
- * call-seq:
2704
- * breakpoint.hit_condition = symbol
2705
- *
2706
- * Sets the hit condition of the breakpoint which must be one of the following values:
2707
- *
2708
- * +nil+ if it is an unconditional breakpoint, or
2709
- * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
2710
- */
2711
- static VALUE
2712
- breakpoint_set_hit_condition(VALUE self, VALUE value)
2713
- {
2714
- debug_breakpoint_t *breakpoint;
2715
- ID id_value;
2716
-
2717
- Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
2718
- id_value = rb_to_id(value);
2719
-
2720
- if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
2721
- breakpoint->hit_condition = HIT_COND_GE;
2722
- else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
2723
- breakpoint->hit_condition = HIT_COND_EQ;
2724
- else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
2725
- breakpoint->hit_condition = HIT_COND_MOD;
2726
- else
2727
- rb_raise(rb_eArgError, "Invalid condition parameter");
2728
- return value;
2729
- }
2730
-
2731
2173
  /*
2732
2174
  * Document-class: Context
2733
2175
  *
2734
- * == Summary
2735
- *
2736
- * Debugger keeps a single instance of this class for each Ruby thread.
2176
+ * The Debugger module keeps a single instance of this class for
2177
+ * each Ruby thread. It contains a call-stack information, thread
2178
+ * information, breakpoint information and the reason the program is
2179
+ * stopped.
2737
2180
  */
2738
2181
  static void
2739
2182
  Init_context()
@@ -2764,46 +2207,53 @@ Init_context()
2764
2207
  rb_define_method(cContext, "frame_self", context_frame_self, -1);
2765
2208
  rb_define_method(cContext, "stack_size", context_stack_size, 0);
2766
2209
  rb_define_method(cContext, "dead?", context_dead, 0);
2767
- rb_define_method(cContext, "breakpoint", context_breakpoint, 0);
2768
- rb_define_method(cContext, "set_breakpoint", context_set_breakpoint, -1);
2210
+ rb_define_method(cContext, "breakpoint",
2211
+ context_breakpoint, 0); /* in breakpoint.c */
2212
+ rb_define_method(cContext, "set_breakpoint",
2213
+ context_set_breakpoint, -1); /* in breakpoint.c */
2769
2214
  }
2770
2215
 
2771
2216
  /*
2772
- * Document-class: Breakpoint
2773
- *
2774
- * == Summary
2217
+ * call-seq:
2218
+ * Debugger.breakpoints -> Array
2775
2219
  *
2776
- * This class represents a breakpoint. It defines position of the breakpoint and
2777
- * condition when this breakpoint should be triggered.
2220
+ * Returns an Array of Breakpoint objects; all the breakpoints that
2221
+ * have been created.
2778
2222
  */
2779
- static void
2780
- Init_breakpoint()
2781
- {
2782
- cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
2783
- rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
2784
- rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
2785
- rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1);
2786
- rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0);
2787
- rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1);
2788
- rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
2789
- rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1);
2790
- rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
2791
- rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1);
2792
- rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0);
2793
- rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0);
2794
- rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1);
2795
- rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0);
2796
- rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1);
2223
+ static VALUE
2224
+ debug_breakpoints(VALUE self)
2225
+ {
2226
+ debug_check_started();
2227
+
2228
+ return rdebug_breakpoints;
2797
2229
  }
2798
2230
 
2231
+ /*
2232
+ * call-seq:
2233
+ * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
2234
+ *
2235
+ * Adds a new breakpoint.
2236
+ * <i>source</i> is a name of a file or a class.
2237
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
2238
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
2239
+ * is activated.
2240
+ */
2241
+ static VALUE
2242
+ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
2243
+ {
2244
+ VALUE result;
2245
+
2246
+ debug_check_started();
2247
+
2248
+ result = create_breakpoint_from_args(argc, argv, ++bkp_count);
2249
+ rb_ary_push(rdebug_breakpoints, result);
2250
+ return result;
2251
+ }
2799
2252
 
2800
2253
  /*
2801
2254
  * Document-class: Debugger
2802
2255
  *
2803
- * == Summary
2804
- *
2805
- * This is a singleton class allows controlling the debugger. Use it to start/stop debugger,
2806
- * set/remove breakpoints, etc.
2256
+ * _Debugger_ is the module name space for ruby-debug.
2807
2257
  */
2808
2258
  #if defined(_WIN32)
2809
2259
  __declspec(dllexport)
@@ -2813,15 +2263,18 @@ Init_ruby_debug()
2813
2263
  {
2814
2264
  mDebugger = rb_define_module("Debugger");
2815
2265
  rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION));
2816
- rb_define_module_function(mDebugger, "start", debug_start, 0);
2266
+ rb_define_module_function(mDebugger, "start_", debug_start, 0);
2817
2267
  rb_define_module_function(mDebugger, "stop", debug_stop, 0);
2818
2268
  rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
2819
2269
  rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
2820
2270
  rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
2821
2271
  rb_define_module_function(mDebugger, "remove_breakpoint",
2822
- debug_remove_breakpoint, 1);
2823
- rb_define_module_function(mDebugger, "catchpoint", debug_catchpoint, 0);
2824
- rb_define_module_function(mDebugger, "catchpoint=", debug_set_catchpoint, 1);
2272
+ rdebug_remove_breakpoint,
2273
+ 1); /* in breakpoint.c */
2274
+ rb_define_module_function(mDebugger, "add_catchpoint",
2275
+ rdebug_add_catchpoint, 1); /* in breakpoint.c */
2276
+ rb_define_module_function(mDebugger, "catchpoints",
2277
+ debug_catchpoints, 0); /* in breakpoint.c */
2825
2278
  rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0);
2826
2279
  rb_define_module_function(mDebugger, "contexts", debug_contexts, 0);
2827
2280
  rb_define_module_function(mDebugger, "current_context", debug_current_context, 0);
@@ -2835,8 +2288,10 @@ Init_ruby_debug()
2835
2288
  rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
2836
2289
  rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0);
2837
2290
  rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1);
2838
- rb_define_module_function(mDebugger, "keep_frame_binding?", debug_keep_frame_binding, 0);
2839
- rb_define_module_function(mDebugger, "keep_frame_binding=", debug_set_keep_frame_binding, 1);
2291
+ rb_define_module_function(mDebugger, "keep_frame_binding?",
2292
+ debug_keep_frame_binding, 0);
2293
+ rb_define_module_function(mDebugger, "keep_frame_binding=",
2294
+ debug_set_keep_frame_binding, 1);
2840
2295
  rb_define_module_function(mDebugger, "track_frame_args?",
2841
2296
  debug_track_frame_args, 0);
2842
2297
  rb_define_module_function(mDebugger, "track_frame_args=",
@@ -2847,24 +2302,25 @@ Init_ruby_debug()
2847
2302
  cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
2848
2303
 
2849
2304
  cDebugThread = rb_define_class_under(mDebugger, "DebugThread", rb_cThread);
2850
- rb_define_singleton_method(cDebugThread, "inherited", debug_thread_inherited, 1);
2305
+ rb_define_singleton_method(cDebugThread, "inherited",
2306
+ debug_thread_inherited, 1);
2851
2307
 
2852
2308
  Init_context();
2853
2309
  Init_breakpoint();
2854
2310
 
2855
- idAtLine = rb_intern("at_line");
2856
2311
  idAtBreakpoint = rb_intern("at_breakpoint");
2857
2312
  idAtCatchpoint = rb_intern("at_catchpoint");
2313
+ idAtLine = rb_intern("at_line");
2314
+ idAtReturn = rb_intern("at_return");
2858
2315
  idAtTracing = rb_intern("at_tracing");
2859
- idEval = rb_intern("eval");
2860
2316
  idList = rb_intern("list");
2861
2317
 
2862
2318
  rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace"));
2863
2319
 
2864
- rb_global_variable(&threads_tbl);
2865
- rb_global_variable(&breakpoints);
2866
- rb_global_variable(&catchpoint);
2867
- rb_global_variable(&locker);
2868
2320
  rb_global_variable(&last_context);
2869
2321
  rb_global_variable(&last_thread);
2322
+ rb_global_variable(&locker);
2323
+ rb_global_variable(&rdebug_breakpoints);
2324
+ rb_global_variable(&rdebug_catchpoints);
2325
+ rb_global_variable(&rdebug_threads_tbl);
2870
2326
  }