ruby-debug-base 0.8.1-mswin32 → 0.9-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/CHANGES +15 -0
- data/ext/ruby_debug.c +316 -97
- data/lib/ruby-debug-base.rb +1 -0
- data/lib/ruby_debug.so +0 -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
data/lib/ruby_debug.so
CHANGED
Binary file
|
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 13:44:21 -04:00
|
8
8
|
summary: Fast Ruby debugger
|
9
9
|
require_paths:
|
10
10
|
- lib
|