ruby-debug-base 0.10.0 → 0.10.1
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 +94 -2
- data/README +30 -1
- data/Rakefile +55 -24
- data/ext/breakpoint.c +581 -0
- data/ext/ruby_debug.c +178 -754
- data/ext/ruby_debug.h +121 -0
- data/lib/ChangeLog +0 -579
- data/lib/ruby-debug-base.rb +67 -38
- 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
- metadata +23 -10
- data/ext/ChangeLog +0 -793
data/ext/ruby_debug.c
CHANGED
@@ -1,11 +1,13 @@
|
|
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
7
|
#include <version.h>
|
7
8
|
|
8
|
-
#define DEBUG_VERSION "0.10.
|
9
|
+
#define DEBUG_VERSION "0.10.1"
|
10
|
+
|
9
11
|
|
10
12
|
#ifdef _WIN32
|
11
13
|
struct FRAME {
|
@@ -43,21 +45,6 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
|
|
43
45
|
#include <env.h>
|
44
46
|
#endif
|
45
47
|
|
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
48
|
#define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1])
|
62
49
|
#define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
|
63
50
|
|
@@ -67,75 +54,10 @@ RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
|
|
67
54
|
|
68
55
|
#define STACK_SIZE_INCREMENT 128
|
69
56
|
|
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
57
|
typedef struct {
|
133
58
|
st_table *tbl;
|
134
59
|
} threads_table_t;
|
135
60
|
|
136
|
-
static VALUE threads_tbl = Qnil;
|
137
|
-
static VALUE breakpoints = Qnil;
|
138
|
-
static VALUE catchpoint = Qnil;
|
139
61
|
static VALUE tracing = Qfalse;
|
140
62
|
static VALUE locker = Qnil;
|
141
63
|
static VALUE post_mortem = Qfalse;
|
@@ -147,20 +69,21 @@ static VALUE last_context = Qnil;
|
|
147
69
|
static VALUE last_thread = Qnil;
|
148
70
|
static debug_context_t *last_debug_context = NULL;
|
149
71
|
|
150
|
-
|
72
|
+
VALUE rdebug_threads_tbl = Qnil; /* Context for each of the threads */
|
73
|
+
VALUE mDebugger; /* Ruby Debugger Module object */
|
74
|
+
|
151
75
|
static VALUE cThreadsTable;
|
152
76
|
static VALUE cContext;
|
153
|
-
static VALUE cBreakpoint;
|
154
77
|
static VALUE cDebugThread;
|
155
78
|
|
156
79
|
static VALUE rb_mObjectSpace;
|
157
80
|
|
158
|
-
static ID idAtLine;
|
159
81
|
static ID idAtBreakpoint;
|
160
82
|
static ID idAtCatchpoint;
|
83
|
+
static ID idAtLine;
|
84
|
+
static ID idAtReturn;
|
161
85
|
static ID idAtTracing;
|
162
86
|
static ID idList;
|
163
|
-
static ID idEval;
|
164
87
|
|
165
88
|
static int start_count = 0;
|
166
89
|
static int thnum_max = 0;
|
@@ -186,6 +109,17 @@ typedef struct locked_thread_t {
|
|
186
109
|
static locked_thread_t *locked_head = NULL;
|
187
110
|
static locked_thread_t *locked_tail = NULL;
|
188
111
|
|
112
|
+
/* "Step", "Next" and "Finish" do their work by saving information
|
113
|
+
about where to stop next. reset_stopping_points removes/resets this
|
114
|
+
information. */
|
115
|
+
inline static void
|
116
|
+
reset_stepping_stop_points(debug_context_t *debug_context)
|
117
|
+
{
|
118
|
+
debug_context->dest_frame = -1;
|
119
|
+
debug_context->stop_line = -1;
|
120
|
+
debug_context->stop_next = -1;
|
121
|
+
}
|
122
|
+
|
189
123
|
inline static VALUE
|
190
124
|
real_class(VALUE klass)
|
191
125
|
{
|
@@ -379,7 +313,7 @@ check_thread_contexts()
|
|
379
313
|
{
|
380
314
|
threads_table_t *threads_table;
|
381
315
|
|
382
|
-
Data_Get_Struct(
|
316
|
+
Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
|
383
317
|
st_foreach(threads_table->tbl, threads_table_check_i, 0);
|
384
318
|
}
|
385
319
|
|
@@ -395,15 +329,6 @@ debug_is_started(VALUE self)
|
|
395
329
|
return IS_STARTED ? Qtrue : Qfalse;
|
396
330
|
}
|
397
331
|
|
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
332
|
static void
|
408
333
|
debug_context_mark(void *data)
|
409
334
|
{
|
@@ -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);
|
@@ -541,6 +466,26 @@ call_at_line(VALUE context, debug_context_t *debug_context, VALUE file, VALUE li
|
|
541
466
|
return rb_protect(call_at_line_unprotected, args, 0);
|
542
467
|
}
|
543
468
|
|
469
|
+
static VALUE
|
470
|
+
call_at_return_unprotected(VALUE args)
|
471
|
+
{
|
472
|
+
VALUE context;
|
473
|
+
context = *RARRAY(args)->ptr;
|
474
|
+
return rb_funcall2(context, idAtReturn, RARRAY(args)->len - 1, RARRAY(args)->ptr + 1);
|
475
|
+
}
|
476
|
+
|
477
|
+
static VALUE
|
478
|
+
call_at_return(VALUE context, debug_context_t *debug_context, VALUE file, VALUE line)
|
479
|
+
{
|
480
|
+
VALUE args;
|
481
|
+
|
482
|
+
last_debugged_thnum = debug_context->thnum;
|
483
|
+
save_current_position(debug_context);
|
484
|
+
|
485
|
+
args = rb_ary_new3(3, context, file, line);
|
486
|
+
return rb_protect(call_at_return_unprotected, args, 0);
|
487
|
+
}
|
488
|
+
|
544
489
|
static void
|
545
490
|
save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debug_context_t *debug_context)
|
546
491
|
{
|
@@ -579,7 +524,7 @@ save_call_frame(rb_event_t event, VALUE self, char *file, int line, ID mid, debu
|
|
579
524
|
#define isdirsep(x) ((x) == '/')
|
580
525
|
#endif
|
581
526
|
|
582
|
-
|
527
|
+
int
|
583
528
|
filename_cmp(VALUE source, char *file)
|
584
529
|
{
|
585
530
|
char *source_ptr, *file_ptr;
|
@@ -606,133 +551,6 @@ filename_cmp(VALUE source, char *file)
|
|
606
551
|
return 1;
|
607
552
|
}
|
608
553
|
|
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
554
|
/*
|
737
555
|
* This is a NASTY HACK. For some reasons rb_f_binding is declared
|
738
556
|
* static in eval.c. So we create a cons up call to binding in C.
|
@@ -750,27 +568,6 @@ create_binding(VALUE self)
|
|
750
568
|
return f_binding(self);
|
751
569
|
}
|
752
570
|
|
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
571
|
inline static debug_frame_t *
|
775
572
|
get_top_frame(debug_context_t *debug_context)
|
776
573
|
{
|
@@ -999,12 +796,9 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
999
796
|
debug_context->breakpoint = Qnil;
|
1000
797
|
}
|
1001
798
|
|
1002
|
-
|
1003
|
-
debug_context
|
1004
|
-
|
1005
|
-
debug_context->stop_next = -1;
|
1006
|
-
|
1007
|
-
call_at_line(context, debug_context, rb_str_new2(file), INT2FIX(line));
|
799
|
+
reset_stepping_stop_points(debug_context);
|
800
|
+
call_at_line(context, debug_context, rb_str_new2(file),
|
801
|
+
INT2FIX(line));
|
1008
802
|
}
|
1009
803
|
break;
|
1010
804
|
}
|
@@ -1056,8 +850,15 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
1056
850
|
{
|
1057
851
|
if(debug_context->stack_size == debug_context->stop_frame)
|
1058
852
|
{
|
1059
|
-
|
1060
|
-
|
853
|
+
if(debug_context->stack_size == 0)
|
854
|
+
save_call_frame(event, self, file, line, mid, debug_context);
|
855
|
+
else
|
856
|
+
set_frame_source(event, debug_context, self, file, line, mid);
|
857
|
+
binding = self? create_binding(self) : Qnil;
|
858
|
+
save_top_binding(debug_context, binding);
|
859
|
+
call_at_return(context, debug_context, rb_str_new2(file),
|
860
|
+
INT2FIX(line));
|
861
|
+
debug_context->dest_frame = -1;
|
1061
862
|
}
|
1062
863
|
while(debug_context->stack_size > 0)
|
1063
864
|
{
|
@@ -1065,7 +866,6 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
1065
866
|
if(debug_context->frames[debug_context->stack_size].orig_id == mid)
|
1066
867
|
break;
|
1067
868
|
}
|
1068
|
-
CTX_FL_SET(debug_context, CTX_FL_ENABLE_BKPT);
|
1069
869
|
break;
|
1070
870
|
}
|
1071
871
|
case RUBY_EVENT_CLASS:
|
@@ -1092,21 +892,43 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
1092
892
|
}
|
1093
893
|
|
1094
894
|
expn_class = rb_obj_class(ruby_errinfo);
|
895
|
+
|
896
|
+
/* This code goes back to the earliest days of ruby-debug. It
|
897
|
+
tends to disallow catching an exception via the
|
898
|
+
"catchpoint" command. To address this one possiblilty is to
|
899
|
+
move this after testing for catchponts. Kent however thinks
|
900
|
+
there may be a misfeature in Ruby's eval.c: the problem was
|
901
|
+
in the fact that Ruby doesn't reset exception flag on the
|
902
|
+
current thread before it calls a notification handler.
|
903
|
+
|
904
|
+
See also the #ifdef'd code below as well.
|
905
|
+
*/
|
906
|
+
#ifdef NORMAL_CODE
|
1095
907
|
if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
|
1096
908
|
{
|
1097
909
|
debug_stop(mDebugger);
|
1098
910
|
break;
|
1099
911
|
}
|
912
|
+
#endif
|
1100
913
|
|
1101
|
-
if(
|
914
|
+
if (rdebug_catchpoints == Qnil ||
|
915
|
+
RHASH(rdebug_catchpoints)->tbl->num_entries == 0)
|
1102
916
|
break;
|
1103
917
|
|
1104
918
|
ancestors = rb_mod_ancestors(expn_class);
|
1105
919
|
for(i = 0; i < RARRAY(ancestors)->len; i++)
|
1106
920
|
{
|
1107
|
-
|
1108
|
-
|
921
|
+
VALUE mod_name;
|
922
|
+
VALUE hit_count;
|
923
|
+
|
924
|
+
aclass = rb_ary_entry(ancestors, i);
|
925
|
+
mod_name = rb_mod_name(aclass);
|
926
|
+
hit_count = rb_hash_aref(rdebug_catchpoints, mod_name);
|
927
|
+
if(hit_count != Qnil)
|
1109
928
|
{
|
929
|
+
hit_count = INT2FIX(FIX2INT(rb_hash_aref(rdebug_catchpoints,
|
930
|
+
mod_name)+1));
|
931
|
+
rb_hash_aset(rdebug_catchpoints, mod_name, hit_count);
|
1110
932
|
debug_context->stop_reason = CTX_STOP_CATCHPOINT;
|
1111
933
|
rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
|
1112
934
|
if(self && binding == Qnil)
|
@@ -1117,6 +939,18 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
1117
939
|
}
|
1118
940
|
}
|
1119
941
|
|
942
|
+
/* If we stop the debugger, we may not be able to trace into
|
943
|
+
code that has an exception handler wrapped around it. So
|
944
|
+
the alternative is to force the user to do his own
|
945
|
+
Debugger.stop. */
|
946
|
+
#ifdef NORMAL_CODE_MOVING_AFTER_
|
947
|
+
if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
|
948
|
+
{
|
949
|
+
debug_stop(mDebugger);
|
950
|
+
break;
|
951
|
+
}
|
952
|
+
#endif
|
953
|
+
|
1120
954
|
break;
|
1121
955
|
}
|
1122
956
|
}
|
@@ -1150,16 +984,20 @@ debug_stop_i(VALUE self)
|
|
1150
984
|
|
1151
985
|
/*
|
1152
986
|
* call-seq:
|
1153
|
-
* Debugger.
|
1154
|
-
* Debugger.
|
987
|
+
* Debugger.start_ -> bool
|
988
|
+
* Debugger.start_ { ... } -> obj
|
989
|
+
*
|
990
|
+
* This method is internal and activates the debugger. Use
|
991
|
+
* Debugger.start (from ruby-debug-base.rb) instead.
|
1155
992
|
*
|
1156
|
-
*
|
1157
|
-
*
|
1158
|
-
*
|
1159
|
-
*
|
993
|
+
* If it's called without a block it returns +true+, unless debugger
|
994
|
+
* was already started. If a block is given, it starts debugger and
|
995
|
+
* yields to block. When the block is finished executing it stops
|
996
|
+
* the debugger with Debugger.stop method.
|
1160
997
|
*
|
1161
|
-
* <i>Note that if you want to stop debugger, you must call
|
1162
|
-
* called Debugger.start
|
998
|
+
* <i>Note that if you want to stop debugger, you must call
|
999
|
+
* Debugger.stop as many time as you called Debugger.start
|
1000
|
+
* method.</i>
|
1163
1001
|
*/
|
1164
1002
|
static VALUE
|
1165
1003
|
debug_start(VALUE self)
|
@@ -1171,9 +1009,10 @@ debug_start(VALUE self)
|
|
1171
1009
|
result = Qfalse;
|
1172
1010
|
else
|
1173
1011
|
{
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1012
|
+
locker = Qnil;
|
1013
|
+
rdebug_breakpoints = rb_ary_new();
|
1014
|
+
rdebug_catchpoints = rb_hash_new();
|
1015
|
+
rdebug_threads_tbl = threads_table_create();
|
1177
1016
|
|
1178
1017
|
rb_add_event_hook(debug_event_hook, RUBY_EVENT_ALL);
|
1179
1018
|
result = Qtrue;
|
@@ -1206,156 +1045,13 @@ debug_stop(VALUE self)
|
|
1206
1045
|
|
1207
1046
|
rb_remove_event_hook(debug_event_hook);
|
1208
1047
|
|
1209
|
-
locker
|
1210
|
-
|
1211
|
-
|
1048
|
+
locker = Qnil;
|
1049
|
+
rdebug_breakpoints = Qnil;
|
1050
|
+
rdebug_threads_tbl = Qnil;
|
1212
1051
|
|
1213
1052
|
return Qtrue;
|
1214
1053
|
}
|
1215
1054
|
|
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
1055
|
static int
|
1360
1056
|
find_last_context_func(VALUE key, VALUE value, VALUE *result)
|
1361
1057
|
{
|
@@ -1383,7 +1079,7 @@ debug_last_interrupted(VALUE self)
|
|
1383
1079
|
|
1384
1080
|
debug_check_started();
|
1385
1081
|
|
1386
|
-
Data_Get_Struct(
|
1082
|
+
Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
|
1387
1083
|
|
1388
1084
|
st_foreach(threads_table->tbl, find_last_context_func, (st_data_t)&result);
|
1389
1085
|
return result;
|
@@ -1451,8 +1147,8 @@ debug_contexts(VALUE self)
|
|
1451
1147
|
thread_context_lookup(thread, &context, NULL);
|
1452
1148
|
rb_ary_push(new_list, context);
|
1453
1149
|
}
|
1454
|
-
threads_table_clear(
|
1455
|
-
Data_Get_Struct(
|
1150
|
+
threads_table_clear(rdebug_threads_tbl);
|
1151
|
+
Data_Get_Struct(rdebug_threads_tbl, threads_table_t, threads_table);
|
1456
1152
|
for(i = 0; i < RARRAY(new_list)->len; i++)
|
1457
1153
|
{
|
1458
1154
|
context = rb_ary_entry(new_list, i);
|
@@ -1676,7 +1372,8 @@ debug_debug_load(int argc, VALUE *argv, VALUE self)
|
|
1676
1372
|
{
|
1677
1373
|
VALUE file, stop, context;
|
1678
1374
|
debug_context_t *debug_context;
|
1679
|
-
|
1375
|
+
int state = 0;
|
1376
|
+
|
1680
1377
|
if(rb_scan_args(argc, argv, "11", &file, &stop) == 1)
|
1681
1378
|
stop = Qfalse;
|
1682
1379
|
|
@@ -1686,8 +1383,14 @@ debug_debug_load(int argc, VALUE *argv, VALUE self)
|
|
1686
1383
|
debug_context->stack_size = 0;
|
1687
1384
|
if(RTEST(stop))
|
1688
1385
|
debug_context->stop_next = 1;
|
1689
|
-
|
1690
|
-
|
1386
|
+
rb_load_protect(file, 0, &state);
|
1387
|
+
if (0 != state) {
|
1388
|
+
VALUE errinfo = ruby_errinfo;
|
1389
|
+
debug_suspend(self);
|
1390
|
+
reset_stepping_stop_points(debug_context);
|
1391
|
+
ruby_errinfo = Qnil;
|
1392
|
+
return errinfo;
|
1393
|
+
}
|
1691
1394
|
debug_stop(self);
|
1692
1395
|
return Qnil;
|
1693
1396
|
}
|
@@ -1836,7 +1539,7 @@ context_step_over(int argc, VALUE *argv, VALUE self)
|
|
1836
1539
|
* call-seq:
|
1837
1540
|
* context.stop_frame(frame)
|
1838
1541
|
*
|
1839
|
-
* Stops when a frame with number +frame+ is activated. Implements +
|
1542
|
+
* Stops when a frame with number +frame+ is activated. Implements +finish+ and +next+ commands.
|
1840
1543
|
*/
|
1841
1544
|
static VALUE
|
1842
1545
|
context_stop_frame(VALUE self, VALUE frame)
|
@@ -2395,50 +2098,6 @@ context_dead(VALUE self)
|
|
2395
2098
|
return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse;
|
2396
2099
|
}
|
2397
2100
|
|
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
2101
|
/*
|
2443
2102
|
* call-seq:
|
2444
2103
|
* context.stop_reason -> sym
|
@@ -2478,256 +2137,6 @@ context_stop_reason(VALUE self)
|
|
2478
2137
|
}
|
2479
2138
|
|
2480
2139
|
|
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
2140
|
/*
|
2732
2141
|
* Document-class: Context
|
2733
2142
|
*
|
@@ -2764,38 +2173,47 @@ Init_context()
|
|
2764
2173
|
rb_define_method(cContext, "frame_self", context_frame_self, -1);
|
2765
2174
|
rb_define_method(cContext, "stack_size", context_stack_size, 0);
|
2766
2175
|
rb_define_method(cContext, "dead?", context_dead, 0);
|
2767
|
-
rb_define_method(cContext, "breakpoint",
|
2768
|
-
|
2176
|
+
rb_define_method(cContext, "breakpoint",
|
2177
|
+
context_breakpoint, 0); /* in breakpoint.c */
|
2178
|
+
rb_define_method(cContext, "set_breakpoint",
|
2179
|
+
context_set_breakpoint, -1); /* in breakpoint.c */
|
2769
2180
|
}
|
2770
2181
|
|
2771
2182
|
/*
|
2772
|
-
*
|
2773
|
-
*
|
2774
|
-
* == Summary
|
2183
|
+
* call-seq:
|
2184
|
+
* Debugger.breakpoints -> array
|
2775
2185
|
*
|
2776
|
-
*
|
2777
|
-
* condition when this breakpoint should be triggered.
|
2186
|
+
* Returns an array of breakpoints.
|
2778
2187
|
*/
|
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);
|
2188
|
+
static VALUE
|
2189
|
+
debug_breakpoints(VALUE self)
|
2190
|
+
{
|
2191
|
+
debug_check_started();
|
2192
|
+
|
2193
|
+
return rdebug_breakpoints;
|
2797
2194
|
}
|
2798
2195
|
|
2196
|
+
/*
|
2197
|
+
* call-seq:
|
2198
|
+
* Debugger.add_breakpoint(source, pos, condition = nil) -> breakpoint
|
2199
|
+
*
|
2200
|
+
* Adds a new breakpoint.
|
2201
|
+
* <i>source</i> is a name of a file or a class.
|
2202
|
+
* <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
|
2203
|
+
* <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
|
2204
|
+
* is activated.
|
2205
|
+
*/
|
2206
|
+
static VALUE
|
2207
|
+
debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
|
2208
|
+
{
|
2209
|
+
VALUE result;
|
2210
|
+
|
2211
|
+
debug_check_started();
|
2212
|
+
|
2213
|
+
result = create_breakpoint_from_args(argc, argv, ++bkp_count);
|
2214
|
+
rb_ary_push(rdebug_breakpoints, result);
|
2215
|
+
return result;
|
2216
|
+
}
|
2799
2217
|
|
2800
2218
|
/*
|
2801
2219
|
* Document-class: Debugger
|
@@ -2813,15 +2231,18 @@ Init_ruby_debug()
|
|
2813
2231
|
{
|
2814
2232
|
mDebugger = rb_define_module("Debugger");
|
2815
2233
|
rb_define_const(mDebugger, "VERSION", rb_str_new2(DEBUG_VERSION));
|
2816
|
-
rb_define_module_function(mDebugger, "
|
2234
|
+
rb_define_module_function(mDebugger, "start_", debug_start, 0);
|
2817
2235
|
rb_define_module_function(mDebugger, "stop", debug_stop, 0);
|
2818
2236
|
rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
|
2819
2237
|
rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
|
2820
2238
|
rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
|
2821
2239
|
rb_define_module_function(mDebugger, "remove_breakpoint",
|
2822
|
-
|
2823
|
-
|
2824
|
-
rb_define_module_function(mDebugger, "
|
2240
|
+
rdebug_remove_breakpoint,
|
2241
|
+
1); /* in breakpoint.c */
|
2242
|
+
rb_define_module_function(mDebugger, "add_catchpoint",
|
2243
|
+
rdebug_add_catchpoint, 1); /* in breakpoint.c */
|
2244
|
+
rb_define_module_function(mDebugger, "catchpoints",
|
2245
|
+
debug_catchpoints, 0); /* in breakpoint.c */
|
2825
2246
|
rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0);
|
2826
2247
|
rb_define_module_function(mDebugger, "contexts", debug_contexts, 0);
|
2827
2248
|
rb_define_module_function(mDebugger, "current_context", debug_current_context, 0);
|
@@ -2835,8 +2256,10 @@ Init_ruby_debug()
|
|
2835
2256
|
rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
|
2836
2257
|
rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0);
|
2837
2258
|
rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1);
|
2838
|
-
rb_define_module_function(mDebugger, "keep_frame_binding?",
|
2839
|
-
|
2259
|
+
rb_define_module_function(mDebugger, "keep_frame_binding?",
|
2260
|
+
debug_keep_frame_binding, 0);
|
2261
|
+
rb_define_module_function(mDebugger, "keep_frame_binding=",
|
2262
|
+
debug_set_keep_frame_binding, 1);
|
2840
2263
|
rb_define_module_function(mDebugger, "track_frame_args?",
|
2841
2264
|
debug_track_frame_args, 0);
|
2842
2265
|
rb_define_module_function(mDebugger, "track_frame_args=",
|
@@ -2847,24 +2270,25 @@ Init_ruby_debug()
|
|
2847
2270
|
cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
|
2848
2271
|
|
2849
2272
|
cDebugThread = rb_define_class_under(mDebugger, "DebugThread", rb_cThread);
|
2850
|
-
rb_define_singleton_method(cDebugThread, "inherited",
|
2273
|
+
rb_define_singleton_method(cDebugThread, "inherited",
|
2274
|
+
debug_thread_inherited, 1);
|
2851
2275
|
|
2852
2276
|
Init_context();
|
2853
2277
|
Init_breakpoint();
|
2854
2278
|
|
2855
|
-
idAtLine = rb_intern("at_line");
|
2856
2279
|
idAtBreakpoint = rb_intern("at_breakpoint");
|
2857
2280
|
idAtCatchpoint = rb_intern("at_catchpoint");
|
2281
|
+
idAtLine = rb_intern("at_line");
|
2282
|
+
idAtReturn = rb_intern("at_return");
|
2858
2283
|
idAtTracing = rb_intern("at_tracing");
|
2859
|
-
idEval = rb_intern("eval");
|
2860
2284
|
idList = rb_intern("list");
|
2861
2285
|
|
2862
2286
|
rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace"));
|
2863
2287
|
|
2864
|
-
rb_global_variable(&threads_tbl);
|
2865
|
-
rb_global_variable(&breakpoints);
|
2866
|
-
rb_global_variable(&catchpoint);
|
2867
|
-
rb_global_variable(&locker);
|
2868
2288
|
rb_global_variable(&last_context);
|
2869
2289
|
rb_global_variable(&last_thread);
|
2290
|
+
rb_global_variable(&locker);
|
2291
|
+
rb_global_variable(&rdebug_breakpoints);
|
2292
|
+
rb_global_variable(&rdebug_catchpoints);
|
2293
|
+
rb_global_variable(&rdebug_threads_tbl);
|
2870
2294
|
}
|