ruby-debug-base 0.10.0-mswin32 → 0.10.4-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|
}
|