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.
- data/CHANGES +15 -0
- data/ext/ruby_debug.c +316 -97
- data/lib/ruby-debug-base.rb +1 -0
- 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.
|
data/ext/ruby_debug.c
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
#include <rubysig.h>
|
5
5
|
#include <st.h>
|
6
6
|
|
7
|
-
#define DEBUG_VERSION "0.
|
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
|
46
|
-
#define
|
47
|
-
#define
|
48
|
-
#define
|
49
|
-
#define
|
50
|
-
#define
|
51
|
-
#define
|
52
|
-
|
53
|
-
|
54
|
-
#define
|
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
|
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
|
-
|
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
|
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
|
-
|
585
|
-
|
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
|
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
|
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
|
-
|
616
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
826
|
-
|
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
|
-
(
|
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(
|
921
|
+
if(breakpoint != Qnil)
|
843
922
|
{
|
844
|
-
breakpoint
|
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
|
-
|
870
|
-
if(
|
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
|
-
|
879
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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.
|
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?
|
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
|
/*
|
data/lib/ruby-debug-base.rb
CHANGED
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.
|
7
|
-
date: 2007-
|
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
|