ruby-debug-base 0.10.0-mswin32 → 0.10.4-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +129 -2
- data/README +43 -6
- data/Rakefile +126 -35
- data/VERSION +3 -0
- data/ext/breakpoint.c +582 -0
- data/ext/extconf.rb +2 -0
- data/ext/ruby_debug.c +229 -773
- data/ext/ruby_debug.h +123 -0
- data/ext/win32/Makefile +31 -23
- data/ext/win32/breakpoint.o +0 -0
- data/ext/win32/ruby_debug.o +0 -0
- data/ext/win32/ruby_debug.so +0 -0
- data/lib/ChangeLog +599 -580
- data/lib/ruby-debug-base.rb +108 -45
- data/lib/ruby_debug.so +0 -0
- data/test/{test-ruby-debug-base.rb → base/base.rb} +27 -29
- data/test/base/binding.rb +31 -0
- data/test/base/catchpoint.rb +26 -0
- data/test/base/reload_bug.rb +8 -0
- metadata +73 -41
- data/ext/ChangeLog +0 -1110
data/ext/extconf.rb
CHANGED
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 <
|
7
|
+
#include <intern.h>
|
7
8
|
|
8
|
-
#define DEBUG_VERSION "0.10.
|
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
|
-
|
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(
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
*
|
738
|
-
* static in eval.c. So
|
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
|
-
|
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(
|
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
|
-
|
1108
|
-
|
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.
|
1154
|
-
* Debugger.
|
990
|
+
* Debugger.start_ -> bool
|
991
|
+
* Debugger.start_ { ... } -> bool
|
1155
992
|
*
|
1156
|
-
* This method activates the debugger.
|
1157
|
-
*
|
1158
|
-
*
|
1159
|
-
*
|
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
|
1162
|
-
*
|
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
|
-
|
1175
|
-
|
1176
|
-
|
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
|
-
|
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
|
1195
|
-
* Debugger.stop as many times as you called
|
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
|
1210
|
-
|
1211
|
-
|
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(
|
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(
|
1455
|
-
Data_Get_Struct(
|
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
|
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
|
-
|
1681
|
-
|
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
|
-
|
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 +
|
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.
|
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
|
-
*
|
2735
|
-
*
|
2736
|
-
*
|
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",
|
2768
|
-
|
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
|
-
*
|
2773
|
-
*
|
2774
|
-
* == Summary
|
2217
|
+
* call-seq:
|
2218
|
+
* Debugger.breakpoints -> Array
|
2775
2219
|
*
|
2776
|
-
*
|
2777
|
-
*
|
2220
|
+
* Returns an Array of Breakpoint objects; all the breakpoints that
|
2221
|
+
* have been created.
|
2778
2222
|
*/
|
2779
|
-
static
|
2780
|
-
|
2781
|
-
{
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
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
|
-
*
|
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, "
|
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
|
-
|
2823
|
-
|
2824
|
-
rb_define_module_function(mDebugger, "
|
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?",
|
2839
|
-
|
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",
|
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
|
}
|