ruby-debug-base 0.8.1 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/CHANGES +15 -0
  2. data/ext/ruby_debug.c +316 -97
  3. data/lib/ruby-debug-base.rb +1 -0
  4. metadata +2 -2
data/CHANGES CHANGED
@@ -1,3 +1,18 @@
1
+ 0.9
2
+ - Kernel#debugger method will start the debugger if it's not running.
3
+ - Added Context#stop_reason method.
4
+ - Calling a method with a block will create a new frame. This changes the behavior of 'next' command. So in order to step into a block, 'step' command must be used. That fixes bug #9629.
5
+ - Added the possibility to add a temporary context-specific breakpoint. Context#breakpoint and Context#set_breakpoint methods are added.
6
+ - 'cont' command now accepts a numerical parameter which implements 'Continue until line' behavior.
7
+ - Added new Context.frame_class method
8
+ - Added new 'framefullpath' setting.
9
+ - Added new 'frameclassname' setting.
10
+ - All Ruby's 'eval' and require/load methods create a new frame. Fixes bug #9686.
11
+
12
+ 0.8.1
13
+ - Added a shortcut module 'debugger'. require "ruby-debug/debugger" will start the debugger and stop at the next line (similar to require 'debug').
14
+ - Fixed remote debugging.
15
+
1
16
  0.8
2
17
  - Extract the base debugger API into a separate gem (ruby-debug-base), so it will be easier to add a new interface.
3
18
  - Added 'set autoirb' setting.
@@ -4,7 +4,7 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.8.1"
7
+ #define DEBUG_VERSION "0.9"
8
8
 
9
9
  #ifdef _WIN32
10
10
  struct FRAME {
@@ -42,16 +42,17 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
42
42
  #include <env.h>
43
43
  #endif
44
44
 
45
- #define CTX_FL_MOVED (1<<1)
46
- #define CTX_FL_SUSPEND (1<<2)
47
- #define CTX_FL_TRACING (1<<3)
48
- #define CTX_FL_SKIPPED (1<<4)
49
- #define CTX_FL_IGNORE (1<<5)
50
- #define CTX_FL_DEAD (1<<6)
51
- #define CTX_FL_WAS_RUNNING (1<<7)
52
-
53
- #define CTX_FL_TEST(c,f) ((c)->flags & (f))
54
- #define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
45
+ #define CTX_FL_SUSPEND (1<<1)
46
+ #define CTX_FL_TRACING (1<<2)
47
+ #define CTX_FL_SKIPPED (1<<3)
48
+ #define CTX_FL_IGNORE (1<<4)
49
+ #define CTX_FL_DEAD (1<<5)
50
+ #define CTX_FL_WAS_RUNNING (1<<6)
51
+ #define CTX_FL_MOVED (1<<7)
52
+ #define CTX_FL_STEPPED (1<<8)
53
+
54
+ #define CTX_FL_TEST(c,f) ((c)->flags & (f))
55
+ #define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
55
56
  #define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
56
57
 
57
58
  #define DID_MOVED (debug_context->last_line != line || \
@@ -60,7 +61,7 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
60
61
 
61
62
  #define IS_STARTED (threads_tbl != Qnil)
62
63
  #define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1])
63
- #define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
64
+ #define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
64
65
 
65
66
  #ifndef min
66
67
  #define min(x,y) ((x) < (y) ? (x) : (y))
@@ -88,10 +89,13 @@ typedef struct {
88
89
  } info;
89
90
  } debug_frame_t;
90
91
 
92
+ enum ctx_stop_reason {CTX_STOP_INIT, CTX_STOP_STEP, CTX_STOP_BREAKPOINT, CTX_STOP_CATCHPOINT};
93
+
91
94
  typedef struct {
92
95
  VALUE thread_id;
93
96
  int thnum;
94
97
  int flags;
98
+ enum ctx_stop_reason stop_reason;
95
99
  int stop_next;
96
100
  int dest_frame;
97
101
  int stop_line;
@@ -101,13 +105,14 @@ typedef struct {
101
105
  debug_frame_t *frames;
102
106
  const char * last_file;
103
107
  int last_line;
108
+ VALUE breakpoint;
104
109
  } debug_context_t;
105
110
 
106
111
  enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
107
112
 
108
113
  typedef struct {
109
114
  int id;
110
- int type;
115
+ enum bp_type type;
111
116
  VALUE source;
112
117
  union
113
118
  {
@@ -146,8 +151,8 @@ static ID idAtLine;
146
151
  static ID idAtBreakpoint;
147
152
  static ID idAtCatchpoint;
148
153
  static ID idAtTracing;
149
- static ID idEval;
150
154
  static ID idList;
155
+ static ID idEval;
151
156
 
152
157
  static int start_count = 0;
153
158
  static int thnum_max = 0;
@@ -171,6 +176,20 @@ typedef struct locked_thread_t {
171
176
  static locked_thread_t *locked_head = NULL;
172
177
  static locked_thread_t *locked_tail = NULL;
173
178
 
179
+ inline static VALUE
180
+ real_class(VALUE klass)
181
+ {
182
+ if (klass) {
183
+ if (TYPE(klass) == T_ICLASS) {
184
+ return RBASIC(klass)->klass;
185
+ }
186
+ else if (FL_TEST(klass, FL_SINGLETON)) {
187
+ return rb_iv_get(klass, "__attached__");
188
+ }
189
+ }
190
+ return klass;
191
+ }
192
+
174
193
  inline static void *
175
194
  ruby_method_ptr(VALUE class, ID meth_id)
176
195
  {
@@ -391,6 +410,7 @@ debug_context_mark(void *data)
391
410
  rb_gc_mark(frame->info.copy.locals);
392
411
  }
393
412
  }
413
+ rb_gc_mark(debug_context->breakpoint);
394
414
  }
395
415
 
396
416
  static void
@@ -416,10 +436,12 @@ debug_context_create(VALUE thread)
416
436
  debug_context->dest_frame = -1;
417
437
  debug_context->stop_line = -1;
418
438
  debug_context->stop_frame = -1;
439
+ debug_context->stop_reason = CTX_STOP_INIT;
419
440
  debug_context->stack_len = STACK_SIZE_INCREMENT;
420
441
  debug_context->frames = ALLOC_N(debug_frame_t, STACK_SIZE_INCREMENT);
421
442
  debug_context->stack_size = 0;
422
443
  debug_context->thread_id = ref2id(thread);
444
+ debug_context->breakpoint = Qnil;
423
445
  if(rb_obj_class(thread) == cDebugThread)
424
446
  CTX_FL_SET(debug_context, CTX_FL_IGNORE);
425
447
  return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context);
@@ -438,6 +460,7 @@ debug_context_dup(debug_context_t *debug_context)
438
460
  new_debug_context->dest_frame = -1;
439
461
  new_debug_context->stop_line = -1;
440
462
  new_debug_context->stop_frame = -1;
463
+ new_debug_context->breakpoint = Qnil;
441
464
  CTX_FL_SET(new_debug_context, CTX_FL_DEAD);
442
465
  new_debug_context->frames = ALLOC_N(debug_frame_t, debug_context->stack_size);
443
466
  new_debug_context->stack_len = debug_context->stack_size;
@@ -567,29 +590,43 @@ filename_cmp(VALUE source, char *file)
567
590
  }
568
591
 
569
592
  static int
593
+ check_breakpoint_by_pos(VALUE breakpoint, char *file, int line)
594
+ {
595
+ debug_breakpoint_t *debug_breakpoint;
596
+
597
+ if(breakpoint == Qnil)
598
+ return 0;
599
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
600
+ if(debug_breakpoint->type != BP_POS_TYPE)
601
+ return 0;
602
+ if(debug_breakpoint->pos.line != line)
603
+ return 0;
604
+ if(filename_cmp(debug_breakpoint->source, file))
605
+ return 1;
606
+ return 0;
607
+ }
608
+
609
+ static VALUE
570
610
  check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
571
611
  {
572
612
  VALUE breakpoint;
573
- debug_breakpoint_t *debug_breakpoint;
574
613
  int i;
575
614
 
576
- if(RARRAY(breakpoints)->len == 0)
577
- return -1;
578
615
  if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
579
- return -1;
616
+ return Qnil;
617
+
618
+ if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
619
+ return debug_context->breakpoint;
580
620
 
621
+ if(RARRAY(breakpoints)->len == 0)
622
+ return Qnil;
581
623
  for(i = 0; i < RARRAY(breakpoints)->len; i++)
582
624
  {
583
625
  breakpoint = rb_ary_entry(breakpoints, i);
584
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
585
- if(debug_breakpoint->type != BP_POS_TYPE)
586
- continue;
587
- if(debug_breakpoint->pos.line != line)
588
- continue;
589
- if(filename_cmp(debug_breakpoint->source, file))
590
- return i;
626
+ if(check_breakpoint_by_pos(breakpoint, file, line))
627
+ return breakpoint;
591
628
  }
592
- return -1;
629
+ return Qnil;
593
630
  }
594
631
 
595
632
  inline static int
@@ -599,28 +636,43 @@ classname_cmp(VALUE name, VALUE klass)
599
636
  }
600
637
 
601
638
  static int
639
+ check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid)
640
+ {
641
+ debug_breakpoint_t *debug_breakpoint;
642
+
643
+ if(breakpoint == Qnil)
644
+ return 0;
645
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
646
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
647
+ return 0;
648
+ if(debug_breakpoint->pos.mid != mid)
649
+ return 0;
650
+ if(classname_cmp(debug_breakpoint->source, klass))
651
+ return 1;
652
+ return 0;
653
+ }
654
+
655
+ static VALUE
602
656
  check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid)
603
657
  {
604
658
  VALUE breakpoint;
605
- debug_breakpoint_t *debug_breakpoint;
606
659
  int i;
607
660
 
608
- if(RARRAY(breakpoints)->len == 0)
609
- return -1;
610
661
  if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
611
- return -1;
662
+ return Qnil;
663
+
664
+ if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid))
665
+ return debug_context->breakpoint;
666
+
667
+ if(RARRAY(breakpoints)->len == 0)
668
+ return Qnil;
612
669
  for(i = 0; i < RARRAY(breakpoints)->len; i++)
613
670
  {
614
671
  breakpoint = rb_ary_entry(breakpoints, i);
615
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
616
- if(debug_breakpoint->type != BP_METHOD_TYPE)
617
- continue;
618
- if(debug_breakpoint->pos.mid != mid)
619
- continue;
620
- if(classname_cmp(debug_breakpoint->source, klass))
621
- return i;
672
+ if(check_breakpoint_by_method(breakpoint, klass, mid))
673
+ return breakpoint;
622
674
  }
623
- return -1;
675
+ return Qnil;
624
676
  }
625
677
 
626
678
  /*
@@ -640,12 +692,6 @@ create_binding(VALUE self)
640
692
  return f_binding(self);
641
693
  }
642
694
 
643
- static VALUE
644
- get_breakpoint_at(int index)
645
- {
646
- return rb_ary_entry(breakpoints, index);
647
- }
648
-
649
695
  static VALUE
650
696
  eval_expression(VALUE args)
651
697
  {
@@ -700,6 +746,17 @@ set_frame_source(rb_event_t event, debug_context_t *debug_context, VALUE self, c
700
746
  }
701
747
  }
702
748
 
749
+ inline static void
750
+ reset_frame_mid(debug_context_t *debug_context)
751
+ {
752
+ debug_frame_t *top_frame;
753
+ top_frame = get_top_frame(debug_context);
754
+ if(top_frame)
755
+ {
756
+ top_frame->id = 0;
757
+ }
758
+ }
759
+
703
760
  static void
704
761
  save_current_position(debug_context_t *debug_context)
705
762
  {
@@ -710,9 +767,10 @@ save_current_position(debug_context_t *debug_context)
710
767
  debug_context->last_file = debug_frame->file;
711
768
  debug_context->last_line = debug_frame->line;
712
769
  CTX_FL_UNSET(debug_context, CTX_FL_MOVED);
770
+ CTX_FL_UNSET(debug_context, CTX_FL_STEPPED);
713
771
  }
714
772
 
715
- static char *
773
+ inline static char *
716
774
  get_event_name(rb_event_t event)
717
775
  {
718
776
  switch (event) {
@@ -737,16 +795,23 @@ get_event_name(rb_event_t event)
737
795
  }
738
796
  }
739
797
 
798
+ inline static int
799
+ c_call_new_frame_p(VALUE klass, ID mid)
800
+ {
801
+ klass = real_class(klass);
802
+ if(rb_block_given_p()) return 1;
803
+ if(klass == rb_cProc || klass == rb_mKernel || klass == rb_cModule) return 1;
804
+ return 0;
805
+ }
740
806
 
741
807
  static void
742
808
  debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
743
809
  {
744
- VALUE thread, context, breakpoint;
745
- VALUE binding = Qnil;
810
+ VALUE thread, context;
811
+ VALUE breakpoint = Qnil, binding = Qnil;
746
812
  debug_context_t *debug_context;
747
813
  char *file = NULL;
748
814
  int line = 0;
749
- int breakpoint_index = -1;
750
815
 
751
816
  hook_count++;
752
817
 
@@ -806,12 +871,23 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
806
871
  fprintf(stderr, "return [%s] %s\n", get_event_name(event), rb_id2name(mid));
807
872
  goto cleanup;
808
873
  }
874
+
875
+ if(event != RUBY_EVENT_LINE)
876
+ CTX_FL_SET(debug_context, CTX_FL_STEPPED);
809
877
 
810
878
  switch(event)
811
879
  {
812
880
  case RUBY_EVENT_LINE:
813
881
  {
814
- set_frame_source(event, debug_context, self, file, line, mid);
882
+
883
+ if(debug_context->stack_size == 0)
884
+ save_call_frame(event, self, file, line, mid, debug_context);
885
+ else
886
+ set_frame_source(event, debug_context, self, file, line, mid);
887
+
888
+ /* avoid useless step on the beginning of 'if' statement */
889
+ if(nd_type(node) == NODE_IF)
890
+ break;
815
891
 
816
892
  if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING))
817
893
  rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line));
@@ -822,30 +898,37 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
822
898
  debug_context->stop_next--;
823
899
  if(debug_context->stop_next < 0)
824
900
  debug_context->stop_next = -1;
825
- /* we check that we actualy moved to another line */
826
- if(DID_MOVED)
901
+ if(CTX_FL_TEST(debug_context, CTX_FL_STEPPED) || CTX_FL_TEST(debug_context, CTX_FL_MOVED))
902
+ {
827
903
  debug_context->stop_line--;
904
+ CTX_FL_UNSET(debug_context, CTX_FL_STEPPED);
905
+ }
828
906
  }
829
907
  else if(debug_context->stack_size < debug_context->dest_frame)
830
908
  {
831
909
  debug_context->stop_next = 0;
832
910
  }
833
911
 
834
- if(debug_context->stack_size == 0)
835
- save_call_frame(event, self, file, line, mid, debug_context);
836
-
837
912
  if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
838
- (breakpoint_index = check_breakpoints_by_pos(debug_context, file, line)) != -1)
913
+ (breakpoint = check_breakpoints_by_pos(debug_context, file, line)) != Qnil)
839
914
  {
840
915
  binding = self? create_binding(self) : Qnil;
916
+ save_top_binding(debug_context, binding);
917
+
918
+ debug_context->stop_reason = CTX_STOP_STEP;
919
+
841
920
  /* check breakpoint expression */
842
- if(breakpoint_index != -1)
921
+ if(breakpoint != Qnil)
843
922
  {
844
- breakpoint = get_breakpoint_at(breakpoint_index);
845
- if(check_breakpoint_expression(breakpoint, binding))
846
- rb_funcall(context, idAtBreakpoint, 1, breakpoint);
847
- else
923
+ if(!check_breakpoint_expression(breakpoint, binding))
848
924
  break;
925
+ if(breakpoint != debug_context->breakpoint)
926
+ {
927
+ debug_context->stop_reason = CTX_STOP_BREAKPOINT;
928
+ rb_funcall(context, idAtBreakpoint, 1, breakpoint);
929
+ }
930
+ else
931
+ debug_context->breakpoint = Qnil;
849
932
  }
850
933
 
851
934
  /* reset all pointers */
@@ -853,21 +936,15 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
853
936
  debug_context->stop_line = -1;
854
937
  debug_context->stop_next = -1;
855
938
 
856
- save_top_binding(debug_context, binding);
857
939
  call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
858
940
  }
859
941
  break;
860
942
  }
861
- case RUBY_EVENT_C_CALL:
862
- {
863
- set_frame_source(event, debug_context, self, file, line, mid);
864
- break;
865
- }
866
943
  case RUBY_EVENT_CALL:
867
944
  {
868
945
  save_call_frame(event, self, file, line, mid, debug_context);
869
- breakpoint_index = check_breakpoints_by_method(debug_context, klass, mid);
870
- if(breakpoint_index != -1)
946
+ breakpoint = check_breakpoints_by_method(debug_context, klass, mid);
947
+ if(breakpoint != Qnil)
871
948
  {
872
949
  debug_frame_t *debug_frame;
873
950
  debug_frame = get_top_frame(debug_context);
@@ -875,16 +952,35 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
875
952
  binding = debug_frame->binding;
876
953
  if(NIL_P(binding) && self)
877
954
  binding = create_binding(self);
878
- breakpoint = get_breakpoint_at(breakpoint_index);
879
- if(check_breakpoint_expression(breakpoint, binding))
955
+ save_top_binding(debug_context, binding);
956
+
957
+ if(!check_breakpoint_expression(breakpoint, binding))
958
+ break;
959
+ if(breakpoint != debug_context->breakpoint)
880
960
  {
881
- save_top_binding(debug_context, binding);
961
+ debug_context->stop_reason = CTX_STOP_BREAKPOINT;
882
962
  rb_funcall(context, idAtBreakpoint, 1, breakpoint);
883
- call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
884
963
  }
964
+ else
965
+ debug_context->breakpoint = Qnil;
966
+ call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
885
967
  }
886
968
  break;
887
969
  }
970
+ case RUBY_EVENT_C_CALL:
971
+ {
972
+ if(c_call_new_frame_p(klass, mid))
973
+ save_call_frame(event, self, file, line, mid, debug_context);
974
+ else
975
+ set_frame_source(event, debug_context, self, file, line, mid);
976
+ break;
977
+ }
978
+ case RUBY_EVENT_C_RETURN:
979
+ {
980
+ /* note if a block is given we fall through! */
981
+ if(!c_call_new_frame_p(klass, mid))
982
+ break;
983
+ }
888
984
  case RUBY_EVENT_RETURN:
889
985
  case RUBY_EVENT_END:
890
986
  {
@@ -903,6 +999,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
903
999
  }
904
1000
  case RUBY_EVENT_CLASS:
905
1001
  {
1002
+ reset_frame_mid(debug_context);
906
1003
  save_call_frame(event, self, file, line, mid, debug_context);
907
1004
  break;
908
1005
  }
@@ -939,6 +1036,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
939
1036
  aclass = rb_ary_entry(ancestors, i);
940
1037
  if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
941
1038
  {
1039
+ debug_context->stop_reason = CTX_STOP_CATCHPOINT;
942
1040
  rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
943
1041
  if(self && binding == Qnil)
944
1042
  binding = create_binding(self);
@@ -950,10 +1048,6 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
950
1048
 
951
1049
  break;
952
1050
  }
953
- case RUBY_EVENT_C_RETURN:
954
- {
955
- break;
956
- }
957
1051
  }
958
1052
 
959
1053
  cleanup:
@@ -1054,26 +1148,13 @@ breakpoint_mark(void *data)
1054
1148
  rb_gc_mark(breakpoint->expr);
1055
1149
  }
1056
1150
 
1057
- /*
1058
- * call-seq:
1059
- * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
1060
- *
1061
- * Adds a new breakpoint.
1062
- * <i>source</i> is a name of a file or a class.
1063
- * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
1064
- * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
1065
- * is activated.
1066
- */
1067
1151
  static VALUE
1068
- debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
1152
+ create_breakpoint_from_args(int argc, VALUE *argv, int id)
1069
1153
  {
1070
1154
  VALUE source, pos, expr;
1071
- VALUE result;
1072
1155
  debug_breakpoint_t *breakpoint;
1073
1156
  int type;
1074
1157
 
1075
- debug_check_started();
1076
-
1077
1158
  if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
1078
1159
  {
1079
1160
  expr = Qnil;
@@ -1084,7 +1165,7 @@ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
1084
1165
  else
1085
1166
  pos = StringValue(pos);
1086
1167
  breakpoint = ALLOC(debug_breakpoint_t);
1087
- breakpoint->id = ++bkp_count;
1168
+ breakpoint->id = id;
1088
1169
  breakpoint->source = source;
1089
1170
  breakpoint->type = type;
1090
1171
  if(type == BP_POS_TYPE)
@@ -1092,7 +1173,27 @@ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
1092
1173
  else
1093
1174
  breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr);
1094
1175
  breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
1095
- result = Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
1176
+ return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
1177
+ }
1178
+
1179
+ /*
1180
+ * call-seq:
1181
+ * Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
1182
+ *
1183
+ * Adds a new breakpoint.
1184
+ * <i>source</i> is a name of a file or a class.
1185
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
1186
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
1187
+ * is activated.
1188
+ */
1189
+ static VALUE
1190
+ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
1191
+ {
1192
+ VALUE result;
1193
+
1194
+ debug_check_started();
1195
+
1196
+ result = create_breakpoint_from_args(argc, argv, ++bkp_count);
1096
1197
  rb_ary_push(breakpoints, result);
1097
1198
  return result;
1098
1199
  }
@@ -1552,9 +1653,8 @@ static VALUE
1552
1653
  debug_at_exit(VALUE self)
1553
1654
  {
1554
1655
  VALUE proc;
1555
- if (!rb_block_given_p()) {
1656
+ if (!rb_block_given_p())
1556
1657
  rb_raise(rb_eArgError, "called without a block");
1557
- }
1558
1658
  proc = rb_block_proc();
1559
1659
  rb_set_end_proc(debug_at_exit_i, proc);
1560
1660
  return proc;
@@ -1574,7 +1674,7 @@ context_stop_next(VALUE self, VALUE steps)
1574
1674
  debug_check_started();
1575
1675
  Data_Get_Struct(self, debug_context_t, debug_context);
1576
1676
  if(FIX2INT(steps) < 0)
1577
- rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
1677
+ rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
1578
1678
  debug_context->stop_next = FIX2INT(steps);
1579
1679
 
1580
1680
  return steps;
@@ -1599,6 +1699,7 @@ context_step_over(int argc, VALUE *argv, VALUE self)
1599
1699
 
1600
1700
  rb_scan_args(argc, argv, "11", &lines, &frame);
1601
1701
  debug_context->stop_line = FIX2INT(lines);
1702
+ CTX_FL_UNSET(debug_context, CTX_FL_STEPPED);
1602
1703
  if(argc == 1)
1603
1704
  {
1604
1705
  debug_context->dest_frame = debug_context->stack_size;
@@ -1663,7 +1764,7 @@ context_frame_binding(VALUE self, VALUE frame)
1663
1764
 
1664
1765
  /*
1665
1766
  * call-seq:
1666
- * context.frame_id(frame) -> sym
1767
+ * context.frame_method(frame) -> sym
1667
1768
  *
1668
1769
  * Returns the sym of the called method.
1669
1770
  */
@@ -1790,6 +1891,36 @@ context_frame_self(VALUE self, VALUE frame)
1790
1891
  return debug_frame->self;
1791
1892
  }
1792
1893
 
1894
+ /*
1895
+ * call-seq:
1896
+ * context.frame_class(frame) -> obj
1897
+ *
1898
+ * Returns the real class of the frame.
1899
+ * It could be different than context.frame_self(frame).class
1900
+ */
1901
+ static VALUE
1902
+ context_frame_class(VALUE self, VALUE frame)
1903
+ {
1904
+ debug_context_t *debug_context;
1905
+ debug_frame_t *debug_frame;
1906
+ VALUE klass;
1907
+
1908
+ debug_check_started();
1909
+ Data_Get_Struct(self, debug_context_t, debug_context);
1910
+
1911
+ debug_frame = GET_FRAME;
1912
+
1913
+ if(CTX_FL_TEST(debug_context, CTX_FL_DEAD))
1914
+ return Qnil;
1915
+
1916
+ klass = debug_frame->info.runtime.frame->last_class;
1917
+ klass = real_class(klass);
1918
+ if(TYPE(klass) == T_CLASS || TYPE(klass) == T_MODULE)
1919
+ return klass;
1920
+ return Qnil;
1921
+ }
1922
+
1923
+
1793
1924
  /*
1794
1925
  * call-seq:
1795
1926
  * context.stack_size-> int
@@ -1977,7 +2108,7 @@ context_ignored(VALUE self)
1977
2108
 
1978
2109
  /*
1979
2110
  * call-seq:
1980
- * context.dead? = bool
2111
+ * context.dead? -> bool
1981
2112
  *
1982
2113
  * Returns +true+ if context doesn't represent a live context and is created
1983
2114
  * during post-mortem exception handling.
@@ -1993,6 +2124,89 @@ context_dead(VALUE self)
1993
2124
  return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse;
1994
2125
  }
1995
2126
 
2127
+ /*
2128
+ * call-seq:
2129
+ * context.breakpoint -> breakpoint
2130
+ *
2131
+ * Returns a context-specific temporary Breakpoint object.
2132
+ */
2133
+ static VALUE
2134
+ context_breakpoint(VALUE self)
2135
+ {
2136
+ debug_context_t *debug_context;
2137
+
2138
+ debug_check_started();
2139
+
2140
+ Data_Get_Struct(self, debug_context_t, debug_context);
2141
+ return debug_context->breakpoint;
2142
+ }
2143
+
2144
+ /*
2145
+ * call-seq:
2146
+ * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
2147
+ *
2148
+ * Sets a context-specific temporary breakpoint, which can be used to implement
2149
+ * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
2150
+ * cleared out.
2151
+ *
2152
+ * <i>source</i> is a name of a file or a class.
2153
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
2154
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
2155
+ * is activated.
2156
+ */
2157
+ static VALUE
2158
+ context_set_breakpoint(int argc, VALUE *argv, VALUE self)
2159
+ {
2160
+ VALUE result;
2161
+ debug_context_t *debug_context;
2162
+
2163
+ debug_check_started();
2164
+
2165
+ Data_Get_Struct(self, debug_context_t, debug_context);
2166
+ result = create_breakpoint_from_args(argc, argv, 0);
2167
+ debug_context->breakpoint = result;
2168
+ return result;
2169
+ }
2170
+
2171
+ /*
2172
+ * call-seq:
2173
+ * context.stop_reason -> sym
2174
+ *
2175
+ * Returns the reason for the stop. It maybe of the following values:
2176
+ * :initial, :step, :breakpoint, :catchpoint, :post-mortem
2177
+ */
2178
+ static VALUE
2179
+ context_stop_reason(VALUE self)
2180
+ {
2181
+ debug_context_t *debug_context;
2182
+ char * sym_name;
2183
+
2184
+ debug_check_started();
2185
+
2186
+ Data_Get_Struct(self, debug_context_t, debug_context);
2187
+
2188
+ switch(debug_context->stop_reason)
2189
+ {
2190
+ case CTX_STOP_STEP:
2191
+ sym_name = "step";
2192
+ break;
2193
+ case CTX_STOP_BREAKPOINT:
2194
+ sym_name = "breakpoint";
2195
+ break;
2196
+ case CTX_STOP_CATCHPOINT:
2197
+ sym_name = "catchpoint";
2198
+ break;
2199
+ case CTX_STOP_INIT:
2200
+ default:
2201
+ sym_name = "initial";
2202
+ }
2203
+ if(CTX_FL_TEST(debug_context, CTX_FL_DEAD))
2204
+ sym_name = "post-mortem";
2205
+
2206
+ return ID2SYM(rb_intern(sym_name));
2207
+ }
2208
+
2209
+
1996
2210
  /*
1997
2211
  * call-seq:
1998
2212
  * breakpoint.source -> string
@@ -2072,6 +2286,7 @@ Init_context()
2072
2286
  rb_define_method(cContext, "stop_frame=", context_stop_frame, 1);
2073
2287
  rb_define_method(cContext, "thread", context_thread, 0);
2074
2288
  rb_define_method(cContext, "thnum", context_thnum, 0);
2289
+ rb_define_method(cContext, "stop_reason", context_stop_reason, 0);
2075
2290
  rb_define_method(cContext, "suspend", context_suspend, 0);
2076
2291
  rb_define_method(cContext, "suspended?", context_is_suspended, 0);
2077
2292
  rb_define_method(cContext, "resume", context_resume, 0);
@@ -2080,12 +2295,16 @@ Init_context()
2080
2295
  rb_define_method(cContext, "ignored?", context_ignored, 0);
2081
2296
  rb_define_method(cContext, "frame_binding", context_frame_binding, 1);
2082
2297
  rb_define_method(cContext, "frame_id", context_frame_id, 1);
2298
+ rb_define_method(cContext, "frame_method", context_frame_id, 1);
2083
2299
  rb_define_method(cContext, "frame_line", context_frame_line, 1);
2084
2300
  rb_define_method(cContext, "frame_file", context_frame_file, 1);
2085
2301
  rb_define_method(cContext, "frame_locals", context_frame_locals, 1);
2086
2302
  rb_define_method(cContext, "frame_self", context_frame_self, 1);
2303
+ rb_define_method(cContext, "frame_class", context_frame_class, 1);
2087
2304
  rb_define_method(cContext, "stack_size", context_stack_size, 0);
2088
2305
  rb_define_method(cContext, "dead?", context_dead, 0);
2306
+ rb_define_method(cContext, "breakpoint", context_breakpoint, 0);
2307
+ rb_define_method(cContext, "set_breakpoint", context_set_breakpoint, -1);
2089
2308
  }
2090
2309
 
2091
2310
  /*
@@ -181,6 +181,7 @@ module Kernel
181
181
  # Stops the current thread after a number of _steps_ made.
182
182
  #
183
183
  def debugger(steps = 1)
184
+ Debugger.start unless Debugger.started?
184
185
  Debugger.current_context.stop_next = steps
185
186
  end
186
187
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: ruby-debug-base
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.8.1
7
- date: 2007-03-19 03:56:11 -04:00
6
+ version: "0.9"
7
+ date: 2007-04-01 12:48:34 -04:00
8
8
  summary: Fast Ruby debugger
9
9
  require_paths:
10
10
  - lib