ruby-debug 0.6.2 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -1
- data/bin/rdebug +5 -5
- data/ext/ruby_debug.c +377 -158
- data/lib/ruby-debug.rb +5 -7
- data/lib/ruby-debug/command.rb +29 -13
- data/lib/ruby-debug/commands/breakpoints.rb +1 -2
- data/lib/ruby-debug/commands/eval.rb +6 -9
- data/lib/ruby-debug/commands/frame.rb +16 -14
- data/lib/ruby-debug/commands/irb.rb +1 -5
- data/lib/ruby-debug/commands/list.rb +1 -9
- data/lib/ruby-debug/commands/settings.rb +41 -0
- data/lib/ruby-debug/commands/stepping.rb +2 -2
- data/lib/ruby-debug/commands/threads.rb +6 -8
- data/lib/ruby-debug/commands/tmate.rb +3 -4
- data/lib/ruby-debug/commands/variables.rb +10 -4
- data/lib/ruby-debug/processor.rb +12 -14
- metadata +15 -15
- data/ext/tags +0 -106
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.7
|
2
|
+
- Eliminated explicit Frame object. Use Context.frame_[binding,file,line] instead.
|
3
|
+
- Fixed help command.
|
4
|
+
- Renamed Debugger.keep_frame_info to Debugger.keep_frame_binding
|
5
|
+
- 'eval' command is available, even when keep_frame_binding is not used.
|
6
|
+
- New 'set' command is available.
|
7
|
+
|
1
8
|
0.6.2
|
2
9
|
- Added thread lookup cache.
|
3
10
|
- Control thread is always started by rdebug script.
|
@@ -105,4 +112,4 @@
|
|
105
112
|
0.1.2 (2006-07-16)
|
106
113
|
========================
|
107
114
|
|
108
|
-
- Initial release.
|
115
|
+
- Initial release.
|
data/bin/rdebug
CHANGED
@@ -16,7 +16,7 @@ options = OpenStruct.new(
|
|
16
16
|
'post_mortem' => false,
|
17
17
|
'script' => nil,
|
18
18
|
'tracing' => false,
|
19
|
-
'
|
19
|
+
'frame_bind' => false
|
20
20
|
)
|
21
21
|
|
22
22
|
opts = OptionParser.new do |opts|
|
@@ -31,10 +31,9 @@ EOB
|
|
31
31
|
opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
|
32
32
|
opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
|
33
33
|
opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
|
34
|
-
opts.on("--cport PORT", Integer, "Port used for contol commands
|
34
|
+
opts.on("--cport PORT", Integer, "Port used for contol commands") {|options.cport|}
|
35
35
|
opts.on("-x", "--trace", "turn on line tracing") {options.tracing = true}
|
36
36
|
opts.on("-n", "--nostop", "Do not stop when stript is loaded") {options.nostop = true}
|
37
|
-
opts.on("-f", "--keep-frame-info", "Keep frame info") {options.frame_info = true}
|
38
37
|
opts.on("-m", "--post-mortem", "Activate post-mortem mode") {options.post_mortem = true}
|
39
38
|
opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path|
|
40
39
|
$LOAD_PATH.unshift(path)
|
@@ -45,6 +44,7 @@ EOB
|
|
45
44
|
exit
|
46
45
|
end
|
47
46
|
end
|
47
|
+
opts.on("--keep-frame-binding", "Keep frame bindings") {options.frame_bind = true}
|
48
48
|
opts.separator ""
|
49
49
|
opts.separator "Common options:"
|
50
50
|
opts.on_tail("--help", "Show this message") do
|
@@ -91,7 +91,7 @@ else
|
|
91
91
|
# set options
|
92
92
|
Debugger.stop_on_connect = !options.nostop
|
93
93
|
Debugger.wait_connection = options.wait
|
94
|
-
Debugger.
|
94
|
+
Debugger.keep_frame_binding = options.frame_bind
|
95
95
|
|
96
96
|
# load user script
|
97
97
|
load "#{ENV["HOME"]}/.rdebugrc" if File.exists?("#{ENV["HOME"]}/.rdebugrc")
|
@@ -121,4 +121,4 @@ else
|
|
121
121
|
# load script
|
122
122
|
Debugger.debug_load Debugger::PROG_SCRIPT
|
123
123
|
end
|
124
|
-
end
|
124
|
+
end
|
data/ext/ruby_debug.c
CHANGED
@@ -4,13 +4,50 @@
|
|
4
4
|
#include <rubysig.h>
|
5
5
|
#include <st.h>
|
6
6
|
|
7
|
-
#define DEBUG_VERSION "0.
|
7
|
+
#define DEBUG_VERSION "0.7"
|
8
|
+
|
9
|
+
#ifdef _WIN32
|
10
|
+
struct FRAME {
|
11
|
+
VALUE self;
|
12
|
+
int argc;
|
13
|
+
ID last_func;
|
14
|
+
ID orig_func;
|
15
|
+
VALUE last_class;
|
16
|
+
struct FRAME *prev;
|
17
|
+
struct FRAME *tmp;
|
18
|
+
struct RNode *node;
|
19
|
+
int iter;
|
20
|
+
int flags;
|
21
|
+
unsigned long uniq;
|
22
|
+
};
|
23
|
+
|
24
|
+
struct SCOPE {
|
25
|
+
struct RBasic super;
|
26
|
+
ID *local_tbl;
|
27
|
+
VALUE *local_vars;
|
28
|
+
int flags;
|
29
|
+
};
|
30
|
+
|
31
|
+
struct RVarmap {
|
32
|
+
struct RBasic super;
|
33
|
+
ID id;
|
34
|
+
VALUE val;
|
35
|
+
struct RVarmap *next;
|
36
|
+
};
|
37
|
+
|
38
|
+
RUBY_EXTERN struct SCOPE *ruby_scope;
|
39
|
+
RUBY_EXTERN struct FRAME *ruby_frame;
|
40
|
+
RUBY_EXTERN struct RVarmap *ruby_dyna_vars;
|
41
|
+
#else
|
42
|
+
#include <env.h>
|
43
|
+
#endif
|
8
44
|
|
9
45
|
#define CTX_FL_MOVED (1<<1)
|
10
46
|
#define CTX_FL_SUSPEND (1<<2)
|
11
47
|
#define CTX_FL_TRACING (1<<3)
|
12
48
|
#define CTX_FL_SKIPPED (1<<4)
|
13
49
|
#define CTX_FL_IGNORE (1<<5)
|
50
|
+
#define CTX_FL_DEAD (1<<6)
|
14
51
|
|
15
52
|
#define CTX_FL_TEST(c,f) ((c)->flags & (f))
|
16
53
|
#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
|
@@ -21,28 +58,45 @@
|
|
21
58
|
strcmp(debug_context->last_file, file) != 0)
|
22
59
|
|
23
60
|
#define IS_STARTED (threads_tbl != Qnil)
|
61
|
+
#define FRAME_N(n) (&debug_context->frames[debug_context->stack_size-(n)-1])
|
62
|
+
#define GET_FRAME (FRAME_N(check_frame_number(debug_context, frame)))
|
24
63
|
|
25
64
|
#ifndef min
|
26
65
|
#define min(x,y) ((x) < (y) ? (x) : (y))
|
27
66
|
#endif
|
28
67
|
|
68
|
+
#define STACK_SIZE_INCREMENT 128
|
69
|
+
|
29
70
|
typedef struct {
|
30
|
-
ID id;
|
31
71
|
VALUE binding;
|
72
|
+
ID id;
|
32
73
|
int line;
|
33
74
|
const char * file;
|
75
|
+
short dead;
|
76
|
+
VALUE self;
|
77
|
+
union {
|
78
|
+
struct {
|
79
|
+
struct FRAME *frame;
|
80
|
+
struct SCOPE *scope;
|
81
|
+
struct RVarmap *dyna_vars;
|
82
|
+
} runtime;
|
83
|
+
struct {
|
84
|
+
VALUE locals;
|
85
|
+
} copy;
|
86
|
+
} info;
|
34
87
|
} debug_frame_t;
|
35
88
|
|
36
89
|
typedef struct {
|
90
|
+
VALUE thread_id;
|
37
91
|
int thnum;
|
38
92
|
int flags;
|
39
93
|
int stop_next;
|
40
94
|
int dest_frame;
|
41
95
|
int stop_line;
|
42
96
|
int stop_frame;
|
43
|
-
|
44
|
-
|
45
|
-
debug_frame_t *
|
97
|
+
int stack_size;
|
98
|
+
int stack_len;
|
99
|
+
debug_frame_t *frames;
|
46
100
|
const char * last_file;
|
47
101
|
int last_line;
|
48
102
|
} debug_context_t;
|
@@ -65,13 +119,13 @@ typedef struct {
|
|
65
119
|
st_table *tbl;
|
66
120
|
} threads_table_t;
|
67
121
|
|
68
|
-
static VALUE threads_tbl
|
69
|
-
static VALUE breakpoints
|
70
|
-
static VALUE catchpoint
|
71
|
-
static VALUE tracing
|
72
|
-
static VALUE locker
|
73
|
-
static VALUE post_mortem
|
74
|
-
static VALUE
|
122
|
+
static VALUE threads_tbl = Qnil;
|
123
|
+
static VALUE breakpoints = Qnil;
|
124
|
+
static VALUE catchpoint = Qnil;
|
125
|
+
static VALUE tracing = Qfalse;
|
126
|
+
static VALUE locker = Qnil;
|
127
|
+
static VALUE post_mortem = Qfalse;
|
128
|
+
static VALUE keep_frame_binding = Qfalse;
|
75
129
|
|
76
130
|
static VALUE last_context = Qnil;
|
77
131
|
static VALUE last_thread = Qnil;
|
@@ -80,7 +134,6 @@ static debug_context_t *last_debug_context = NULL;
|
|
80
134
|
static VALUE mDebugger;
|
81
135
|
static VALUE cThreadsTable;
|
82
136
|
static VALUE cContext;
|
83
|
-
static VALUE cFrame;
|
84
137
|
static VALUE cBreakpoint;
|
85
138
|
|
86
139
|
static VALUE rb_mObjectSpace;
|
@@ -102,9 +155,10 @@ static unsigned long hook_count = 0;
|
|
102
155
|
static VALUE create_binding(VALUE);
|
103
156
|
static VALUE debug_stop(VALUE);
|
104
157
|
static void save_current_position(debug_context_t *);
|
158
|
+
static VALUE context_copy_locals(debug_frame_t *);
|
105
159
|
|
106
160
|
typedef struct locked_thread_t {
|
107
|
-
|
161
|
+
VALUE thread_id;
|
108
162
|
struct locked_thread_t *next;
|
109
163
|
} locked_thread_t;
|
110
164
|
|
@@ -120,10 +174,10 @@ ruby_method_ptr(VALUE class, ID meth_id)
|
|
120
174
|
return (void *)method->u1.value;
|
121
175
|
}
|
122
176
|
|
123
|
-
inline static
|
177
|
+
inline static VALUE
|
124
178
|
ref2id(VALUE obj)
|
125
179
|
{
|
126
|
-
return
|
180
|
+
return rb_obj_id(obj);
|
127
181
|
}
|
128
182
|
|
129
183
|
static VALUE
|
@@ -141,13 +195,14 @@ id2ref_unprotected(VALUE id)
|
|
141
195
|
static VALUE
|
142
196
|
id2ref_error()
|
143
197
|
{
|
198
|
+
rb_p(ruby_errinfo);
|
144
199
|
return Qnil;
|
145
200
|
}
|
146
201
|
|
147
202
|
static VALUE
|
148
|
-
id2ref(
|
203
|
+
id2ref(VALUE id)
|
149
204
|
{
|
150
|
-
return rb_rescue(id2ref_unprotected,
|
205
|
+
return rb_rescue(id2ref_unprotected, id, id2ref_error, 0);
|
151
206
|
}
|
152
207
|
|
153
208
|
inline static VALUE
|
@@ -157,7 +212,7 @@ context_thread_0(debug_context_t *debug_context)
|
|
157
212
|
}
|
158
213
|
|
159
214
|
static int
|
160
|
-
is_in_locked(
|
215
|
+
is_in_locked(VALUE thread_id)
|
161
216
|
{
|
162
217
|
locked_thread_t *node;
|
163
218
|
|
@@ -175,7 +230,7 @@ static void
|
|
175
230
|
add_to_locked(VALUE thread)
|
176
231
|
{
|
177
232
|
locked_thread_t *node;
|
178
|
-
|
233
|
+
VALUE thread_id = ref2id(thread);
|
179
234
|
|
180
235
|
if(is_in_locked(thread_id))
|
181
236
|
return;
|
@@ -314,16 +369,34 @@ debug_check_started()
|
|
314
369
|
}
|
315
370
|
|
316
371
|
static void
|
317
|
-
debug_context_mark(void*
|
372
|
+
debug_context_mark(void *data)
|
318
373
|
{
|
374
|
+
debug_frame_t *frame;
|
375
|
+
int i;
|
376
|
+
|
319
377
|
debug_context_t *debug_context = (debug_context_t *)data;
|
320
|
-
|
378
|
+
for(i = 0; i < debug_context->stack_size; i++)
|
379
|
+
{
|
380
|
+
frame = &(debug_context->frames[i]);
|
381
|
+
rb_gc_mark(frame->binding);
|
382
|
+
rb_gc_mark(frame->self);
|
383
|
+
if(frame->dead)
|
384
|
+
{
|
385
|
+
rb_gc_mark(frame->info.copy.locals);
|
386
|
+
}
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
static void
|
391
|
+
debug_context_free(void *data)
|
392
|
+
{
|
393
|
+
debug_context_t *debug_context = (debug_context_t *)data;
|
394
|
+
xfree(debug_context->frames);
|
321
395
|
}
|
322
396
|
|
323
397
|
static VALUE
|
324
398
|
debug_context_create(VALUE thread)
|
325
399
|
{
|
326
|
-
VALUE result;
|
327
400
|
debug_context_t *debug_context;
|
328
401
|
|
329
402
|
debug_context = ALLOC(debug_context_t);
|
@@ -337,18 +410,45 @@ debug_context_create(VALUE thread)
|
|
337
410
|
debug_context->dest_frame = -1;
|
338
411
|
debug_context->stop_line = -1;
|
339
412
|
debug_context->stop_frame = -1;
|
340
|
-
debug_context->
|
341
|
-
debug_context->
|
413
|
+
debug_context->stack_len = STACK_SIZE_INCREMENT;
|
414
|
+
debug_context->frames = ALLOC_N(debug_frame_t, STACK_SIZE_INCREMENT);
|
415
|
+
debug_context->stack_size = 0;
|
342
416
|
debug_context->thread_id = ref2id(thread);
|
343
|
-
|
344
|
-
|
417
|
+
return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, debug_context);
|
418
|
+
}
|
419
|
+
|
420
|
+
static VALUE
|
421
|
+
debug_context_dup(debug_context_t *debug_context)
|
422
|
+
{
|
423
|
+
debug_context_t *new_debug_context;
|
424
|
+
debug_frame_t *new_frame, *old_frame;
|
425
|
+
int i;
|
426
|
+
|
427
|
+
new_debug_context = ALLOC(debug_context_t);
|
428
|
+
memcpy(new_debug_context, debug_context, sizeof(debug_context_t));
|
429
|
+
new_debug_context->stop_next = -1;
|
430
|
+
new_debug_context->dest_frame = -1;
|
431
|
+
new_debug_context->stop_line = -1;
|
432
|
+
new_debug_context->stop_frame = -1;
|
433
|
+
CTX_FL_SET(new_debug_context, CTX_FL_DEAD);
|
434
|
+
new_debug_context->frames = ALLOC_N(debug_frame_t, debug_context->stack_size);
|
435
|
+
new_debug_context->stack_len = debug_context->stack_size;
|
436
|
+
memcpy(new_debug_context->frames, debug_context->frames, sizeof(debug_frame_t) * debug_context->stack_size);
|
437
|
+
for(i = 0; i < debug_context->stack_size; i++)
|
438
|
+
{
|
439
|
+
new_frame = &(new_debug_context->frames[i]);
|
440
|
+
old_frame = &(debug_context->frames[i]);
|
441
|
+
new_frame->dead = 1;
|
442
|
+
new_frame->info.copy.locals = context_copy_locals(old_frame);
|
443
|
+
}
|
444
|
+
return Data_Wrap_Struct(cContext, debug_context_mark, debug_context_free, new_debug_context);
|
345
445
|
}
|
346
446
|
|
347
447
|
static void
|
348
448
|
thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context)
|
349
449
|
{
|
350
450
|
threads_table_t *threads_table;
|
351
|
-
|
451
|
+
VALUE thread_id;
|
352
452
|
debug_context_t *l_debug_context;
|
353
453
|
|
354
454
|
debug_check_started();
|
@@ -377,13 +477,6 @@ thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_cont
|
|
377
477
|
last_debug_context = l_debug_context;
|
378
478
|
}
|
379
479
|
|
380
|
-
static void
|
381
|
-
debug_frame_mark(void *data)
|
382
|
-
{
|
383
|
-
debug_frame_t *debug_frame = (debug_frame_t *)data;
|
384
|
-
rb_gc_mark(debug_frame->binding);
|
385
|
-
}
|
386
|
-
|
387
480
|
static VALUE
|
388
481
|
call_at_line_unprotected(VALUE args)
|
389
482
|
{
|
@@ -407,19 +500,28 @@ call_at_line(VALUE context, debug_context_t *debug_context, VALUE file, VALUE li
|
|
407
500
|
static void
|
408
501
|
save_call_frame(VALUE self, char *file, int line, ID mid, debug_context_t *debug_context)
|
409
502
|
{
|
410
|
-
VALUE
|
503
|
+
VALUE binding;
|
411
504
|
debug_frame_t *debug_frame;
|
505
|
+
int frame_n;
|
506
|
+
|
507
|
+
binding = self && RTEST(keep_frame_binding)? create_binding(self) : Qnil;
|
412
508
|
|
413
|
-
|
414
|
-
|
509
|
+
frame_n = debug_context->stack_size++;
|
510
|
+
if(frame_n >= debug_context->stack_len)
|
511
|
+
{
|
512
|
+
debug_context->stack_len += STACK_SIZE_INCREMENT;
|
513
|
+
debug_context->frames = REALLOC_N(debug_context->frames, debug_frame_t, debug_context->stack_len);
|
514
|
+
}
|
515
|
+
debug_frame = &debug_context->frames[frame_n];
|
415
516
|
debug_frame->file = file;
|
416
517
|
debug_frame->line = line;
|
417
518
|
debug_frame->binding = binding;
|
418
519
|
debug_frame->id = mid;
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
520
|
+
debug_frame->dead = 0;
|
521
|
+
debug_frame->self = self;
|
522
|
+
debug_frame->info.runtime.frame = ruby_frame;
|
523
|
+
debug_frame->info.runtime.scope = ruby_scope;
|
524
|
+
debug_frame->info.runtime.dyna_vars = ruby_dyna_vars;
|
423
525
|
}
|
424
526
|
|
425
527
|
#if defined DOSISH
|
@@ -559,22 +661,10 @@ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
|
|
559
661
|
inline static debug_frame_t *
|
560
662
|
get_top_frame(debug_context_t *debug_context)
|
561
663
|
{
|
562
|
-
|
563
|
-
debug_frame_t *debug_frame;
|
564
|
-
if(RARRAY(debug_context->frames)->len == 0)
|
664
|
+
if(debug_context->stack_size == 0)
|
565
665
|
return NULL;
|
566
666
|
else
|
567
|
-
|
568
|
-
if(debug_context->top_frame == NULL)
|
569
|
-
{
|
570
|
-
frame = RARRAY(debug_context->frames)->ptr[RARRAY(debug_context->frames)->len-1];
|
571
|
-
Data_Get_Struct(frame, debug_frame_t, debug_frame);
|
572
|
-
debug_context->top_frame = debug_frame;
|
573
|
-
}
|
574
|
-
else
|
575
|
-
debug_frame = debug_context->top_frame;
|
576
|
-
return debug_frame;
|
577
|
-
}
|
667
|
+
return &(debug_context->frames[debug_context->stack_size-1]);
|
578
668
|
}
|
579
669
|
|
580
670
|
inline static void
|
@@ -586,7 +676,7 @@ save_top_binding(debug_context_t *debug_context, VALUE binding)
|
|
586
676
|
debug_frame->binding = binding;
|
587
677
|
}
|
588
678
|
|
589
|
-
static void
|
679
|
+
inline static void
|
590
680
|
set_frame_source(debug_context_t *debug_context, char *file, int line)
|
591
681
|
{
|
592
682
|
debug_frame_t *top_frame;
|
@@ -598,6 +688,17 @@ set_frame_source(debug_context_t *debug_context, char *file, int line)
|
|
598
688
|
}
|
599
689
|
}
|
600
690
|
|
691
|
+
inline static void
|
692
|
+
set_dyna_vars(debug_context_t *debug_context)
|
693
|
+
{
|
694
|
+
debug_frame_t *top_frame;
|
695
|
+
top_frame = get_top_frame(debug_context);
|
696
|
+
if(top_frame)
|
697
|
+
{
|
698
|
+
top_frame->info.runtime.dyna_vars = ruby_dyna_vars;
|
699
|
+
}
|
700
|
+
}
|
701
|
+
|
601
702
|
static void
|
602
703
|
save_current_position(debug_context_t *debug_context)
|
603
704
|
{
|
@@ -670,12 +771,13 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
670
771
|
case RUBY_EVENT_LINE:
|
671
772
|
{
|
672
773
|
set_frame_source(debug_context, file, line);
|
774
|
+
set_dyna_vars(debug_context);
|
673
775
|
|
674
776
|
if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING))
|
675
777
|
rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line));
|
676
778
|
|
677
779
|
if(debug_context->dest_frame == -1 ||
|
678
|
-
|
780
|
+
debug_context->stack_size == debug_context->dest_frame)
|
679
781
|
{
|
680
782
|
debug_context->stop_next--;
|
681
783
|
if(debug_context->stop_next < 0)
|
@@ -684,12 +786,12 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
684
786
|
if(DID_MOVED)
|
685
787
|
debug_context->stop_line--;
|
686
788
|
}
|
687
|
-
else if(
|
789
|
+
else if(debug_context->stack_size < debug_context->dest_frame)
|
688
790
|
{
|
689
791
|
debug_context->stop_next = 0;
|
690
792
|
}
|
691
793
|
|
692
|
-
if(
|
794
|
+
if(debug_context->stack_size == 0)
|
693
795
|
save_call_frame(self, file, line, mid, debug_context);
|
694
796
|
|
695
797
|
if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
|
@@ -746,13 +848,13 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
746
848
|
case RUBY_EVENT_RETURN:
|
747
849
|
case RUBY_EVENT_END:
|
748
850
|
{
|
749
|
-
if(
|
851
|
+
if(debug_context->stack_size == debug_context->stop_frame)
|
750
852
|
{
|
751
853
|
debug_context->stop_next = 1;
|
752
854
|
debug_context->stop_frame = 0;
|
753
855
|
}
|
754
|
-
|
755
|
-
|
856
|
+
if(debug_context->stack_size > 0)
|
857
|
+
debug_context->stack_size--;
|
756
858
|
break;
|
757
859
|
}
|
758
860
|
case RUBY_EVENT_CLASS:
|
@@ -772,7 +874,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
772
874
|
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), rb_str_new2(file));
|
773
875
|
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), INT2FIX(line));
|
774
876
|
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_binding"), binding);
|
775
|
-
rb_ivar_set(ruby_errinfo, rb_intern("@
|
877
|
+
rb_ivar_set(ruby_errinfo, rb_intern("@__debug_context"), debug_context_dup(debug_context));
|
776
878
|
}
|
777
879
|
|
778
880
|
expn_class = rb_obj_class(ruby_errinfo);
|
@@ -1270,26 +1372,26 @@ debug_set_post_mortem(VALUE self, VALUE value)
|
|
1270
1372
|
|
1271
1373
|
/*
|
1272
1374
|
* call-seq:
|
1273
|
-
* Debugger.
|
1375
|
+
* Debugger.keep_frame_binding? -> bool
|
1274
1376
|
*
|
1275
1377
|
* Returns +true+ if the debugger will collect frame bindings.
|
1276
1378
|
*/
|
1277
1379
|
static VALUE
|
1278
|
-
|
1380
|
+
debug_keep_frame_binding(VALUE self)
|
1279
1381
|
{
|
1280
|
-
return
|
1382
|
+
return keep_frame_binding;
|
1281
1383
|
}
|
1282
1384
|
|
1283
1385
|
/*
|
1284
1386
|
* call-seq:
|
1285
|
-
* Debugger.
|
1387
|
+
* Debugger.keep_frame_binding = bool
|
1286
1388
|
*
|
1287
|
-
* Setting to +true+ will make the debugger
|
1389
|
+
* Setting to +true+ will make the debugger create frame bindings.
|
1288
1390
|
*/
|
1289
1391
|
static VALUE
|
1290
|
-
|
1392
|
+
debug_set_keep_frame_binding(VALUE self, VALUE value)
|
1291
1393
|
{
|
1292
|
-
|
1394
|
+
keep_frame_binding = RTEST(value) ? Qtrue : Qfalse;
|
1293
1395
|
return value;
|
1294
1396
|
}
|
1295
1397
|
|
@@ -1310,7 +1412,7 @@ debug_debug_load(VALUE self, VALUE file)
|
|
1310
1412
|
|
1311
1413
|
context = debug_current_context(self);
|
1312
1414
|
Data_Get_Struct(context, debug_context_t, debug_context);
|
1313
|
-
|
1415
|
+
debug_context->stack_size = 0;
|
1314
1416
|
rb_load(file, 0);
|
1315
1417
|
|
1316
1418
|
debug_stop(self);
|
@@ -1401,7 +1503,6 @@ context_stop_next(VALUE self, VALUE steps)
|
|
1401
1503
|
debug_context_t *debug_context;
|
1402
1504
|
|
1403
1505
|
debug_check_started();
|
1404
|
-
|
1405
1506
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1406
1507
|
if(FIX2INT(steps) < 0)
|
1407
1508
|
rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
|
@@ -1423,22 +1524,21 @@ context_step_over(int argc, VALUE *argv, VALUE self)
|
|
1423
1524
|
debug_context_t *debug_context;
|
1424
1525
|
|
1425
1526
|
debug_check_started();
|
1426
|
-
|
1427
1527
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1428
|
-
if(
|
1528
|
+
if(debug_context->stack_size == 0)
|
1429
1529
|
rb_raise(rb_eRuntimeError, "No frames collected.");
|
1430
1530
|
|
1431
1531
|
rb_scan_args(argc, argv, "11", &lines, &frame);
|
1432
1532
|
debug_context->stop_line = FIX2INT(lines);
|
1433
1533
|
if(argc == 1)
|
1434
1534
|
{
|
1435
|
-
debug_context->dest_frame =
|
1535
|
+
debug_context->dest_frame = debug_context->stack_size;
|
1436
1536
|
}
|
1437
1537
|
else
|
1438
1538
|
{
|
1439
|
-
if(FIX2INT(frame) < 0 && FIX2INT(frame) >=
|
1539
|
+
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
|
1440
1540
|
rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
|
1441
|
-
debug_context->dest_frame =
|
1541
|
+
debug_context->dest_frame = debug_context->stack_size - FIX2INT(frame);
|
1442
1542
|
}
|
1443
1543
|
|
1444
1544
|
return Qnil;
|
@@ -1456,28 +1556,182 @@ context_stop_frame(VALUE self, VALUE frame)
|
|
1456
1556
|
debug_context_t *debug_context;
|
1457
1557
|
|
1458
1558
|
debug_check_started();
|
1459
|
-
|
1460
1559
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1461
|
-
if(FIX2INT(frame) < 0 && FIX2INT(frame) >=
|
1560
|
+
if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
|
1462
1561
|
rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
|
1463
|
-
debug_context->stop_frame =
|
1562
|
+
debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame);
|
1464
1563
|
|
1465
1564
|
return frame;
|
1466
1565
|
}
|
1467
1566
|
|
1567
|
+
inline static int
|
1568
|
+
check_frame_number(debug_context_t *debug_context, VALUE frame)
|
1569
|
+
{
|
1570
|
+
int frame_n;
|
1571
|
+
|
1572
|
+
frame_n = FIX2INT(frame);
|
1573
|
+
if(frame_n < 0 || frame_n >= debug_context->stack_size)
|
1574
|
+
rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)",
|
1575
|
+
frame_n, debug_context->stack_size);
|
1576
|
+
return frame_n;
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
/*
|
1580
|
+
* call-seq:
|
1581
|
+
* context.frame_binding(frame) -> binding
|
1582
|
+
*
|
1583
|
+
* Returns frame's binding.
|
1584
|
+
*/
|
1585
|
+
static VALUE
|
1586
|
+
context_frame_binding(VALUE self, VALUE frame)
|
1587
|
+
{
|
1588
|
+
debug_context_t *debug_context;
|
1589
|
+
|
1590
|
+
debug_check_started();
|
1591
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1592
|
+
return GET_FRAME->binding;
|
1593
|
+
}
|
1594
|
+
|
1595
|
+
/*
|
1596
|
+
* call-seq:
|
1597
|
+
* context.frame_id(frame) -> sym
|
1598
|
+
*
|
1599
|
+
* Returns the sym of the called method.
|
1600
|
+
*/
|
1601
|
+
static VALUE
|
1602
|
+
context_frame_id(VALUE self, VALUE frame)
|
1603
|
+
{
|
1604
|
+
|
1605
|
+
debug_context_t *debug_context;
|
1606
|
+
ID id;
|
1607
|
+
|
1608
|
+
debug_check_started();
|
1609
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1610
|
+
|
1611
|
+
id = GET_FRAME->id;
|
1612
|
+
return id ? ID2SYM(id): Qnil;
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
/*
|
1616
|
+
* call-seq:
|
1617
|
+
* context.frame_line(frame) -> int
|
1618
|
+
*
|
1619
|
+
* Returns the line number in the file.
|
1620
|
+
*/
|
1621
|
+
static VALUE
|
1622
|
+
context_frame_line(VALUE self, VALUE frame)
|
1623
|
+
{
|
1624
|
+
debug_context_t *debug_context;
|
1625
|
+
|
1626
|
+
debug_check_started();
|
1627
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1628
|
+
|
1629
|
+
return INT2FIX(GET_FRAME->line);
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
/*
|
1633
|
+
* call-seq:
|
1634
|
+
* context.frame_file(frame) -> string
|
1635
|
+
*
|
1636
|
+
* Returns the name of the file.
|
1637
|
+
*/
|
1638
|
+
static VALUE
|
1639
|
+
context_frame_file(VALUE self, VALUE frame)
|
1640
|
+
{
|
1641
|
+
debug_context_t *debug_context;
|
1642
|
+
|
1643
|
+
debug_check_started();
|
1644
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1645
|
+
|
1646
|
+
return rb_str_new2(GET_FRAME->file);
|
1647
|
+
}
|
1648
|
+
|
1649
|
+
static VALUE
|
1650
|
+
context_copy_locals(debug_frame_t *debug_frame)
|
1651
|
+
{
|
1652
|
+
ID *tbl;
|
1653
|
+
int n, i;
|
1654
|
+
struct SCOPE *scope;
|
1655
|
+
struct RVarmap *vars;
|
1656
|
+
VALUE hash = rb_hash_new();
|
1657
|
+
|
1658
|
+
scope = debug_frame->info.runtime.scope;
|
1659
|
+
tbl = scope->local_tbl;
|
1660
|
+
|
1661
|
+
if (tbl && scope->local_vars) {
|
1662
|
+
n = *tbl++;
|
1663
|
+
for (i=2; i<n; i++) { /* skip first 2 ($_ and $~) */
|
1664
|
+
if (!rb_is_local_id(tbl[i])) continue; /* skip flip states */
|
1665
|
+
rb_hash_aset(hash, rb_str_new2(rb_id2name(tbl[i])), scope->local_vars[i]);
|
1666
|
+
}
|
1667
|
+
}
|
1668
|
+
|
1669
|
+
vars = debug_frame->info.runtime.dyna_vars;
|
1670
|
+
while (vars) {
|
1671
|
+
if (vars->id && rb_is_local_id(vars->id)) { /* skip $_, $~ and flip states */
|
1672
|
+
rb_hash_aset(hash, rb_str_new2(rb_id2name(vars->id)), vars->val);
|
1673
|
+
}
|
1674
|
+
vars = vars->next;
|
1675
|
+
}
|
1676
|
+
return hash;
|
1677
|
+
}
|
1678
|
+
|
1468
1679
|
/*
|
1469
1680
|
* call-seq:
|
1470
|
-
* context.
|
1681
|
+
* context.frame_locals(frame) -> hash
|
1471
1682
|
*
|
1472
|
-
* Returns
|
1683
|
+
* Returns frame's local variables.
|
1473
1684
|
*/
|
1474
1685
|
static VALUE
|
1475
|
-
|
1686
|
+
context_frame_locals(VALUE self, VALUE frame)
|
1476
1687
|
{
|
1477
1688
|
debug_context_t *debug_context;
|
1689
|
+
debug_frame_t *debug_frame;
|
1478
1690
|
|
1691
|
+
debug_check_started();
|
1479
1692
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1480
|
-
|
1693
|
+
|
1694
|
+
debug_frame = GET_FRAME;
|
1695
|
+
if(debug_frame->dead)
|
1696
|
+
return debug_frame->info.copy.locals;
|
1697
|
+
else
|
1698
|
+
return context_copy_locals(debug_frame);
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
/*
|
1702
|
+
* call-seq:
|
1703
|
+
* context.frame_self(frame) -> obj
|
1704
|
+
*
|
1705
|
+
* Returns self object of the frame.
|
1706
|
+
*/
|
1707
|
+
static VALUE
|
1708
|
+
context_frame_self(VALUE self, VALUE frame)
|
1709
|
+
{
|
1710
|
+
debug_context_t *debug_context;
|
1711
|
+
debug_frame_t *debug_frame;
|
1712
|
+
|
1713
|
+
debug_check_started();
|
1714
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1715
|
+
|
1716
|
+
debug_frame = GET_FRAME;
|
1717
|
+
return debug_frame->self;
|
1718
|
+
}
|
1719
|
+
|
1720
|
+
/*
|
1721
|
+
* call-seq:
|
1722
|
+
* context.stack_size-> int
|
1723
|
+
*
|
1724
|
+
* Returns the size of the context stack.
|
1725
|
+
*/
|
1726
|
+
static VALUE
|
1727
|
+
context_stack_size(VALUE self)
|
1728
|
+
{
|
1729
|
+
debug_context_t *debug_context;
|
1730
|
+
|
1731
|
+
debug_check_started();
|
1732
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1733
|
+
|
1734
|
+
return INT2FIX(debug_context->stack_size);
|
1481
1735
|
}
|
1482
1736
|
|
1483
1737
|
/*
|
@@ -1491,6 +1745,7 @@ context_thread(VALUE self)
|
|
1491
1745
|
{
|
1492
1746
|
debug_context_t *debug_context;
|
1493
1747
|
|
1748
|
+
debug_check_started();
|
1494
1749
|
Data_Get_Struct(self, debug_context_t, debug_context);
|
1495
1750
|
return context_thread_0(debug_context);
|
1496
1751
|
}
|
@@ -1530,6 +1785,23 @@ context_suspend(VALUE self)
|
|
1530
1785
|
return Qnil;
|
1531
1786
|
}
|
1532
1787
|
|
1788
|
+
/*
|
1789
|
+
* call-seq:
|
1790
|
+
* context.suspended? -> bool
|
1791
|
+
*
|
1792
|
+
* Returns +true+ if the thread is suspended by debugger.
|
1793
|
+
*/
|
1794
|
+
static VALUE
|
1795
|
+
context_is_suspended(VALUE self)
|
1796
|
+
{
|
1797
|
+
debug_context_t *debug_context;
|
1798
|
+
|
1799
|
+
debug_check_started();
|
1800
|
+
|
1801
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1802
|
+
return CTX_FL_TEST(debug_context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
|
1803
|
+
}
|
1804
|
+
|
1533
1805
|
/*
|
1534
1806
|
* call-seq:
|
1535
1807
|
* context.resume -> nil
|
@@ -1629,62 +1901,20 @@ context_set_ignore(VALUE self, VALUE value)
|
|
1629
1901
|
|
1630
1902
|
/*
|
1631
1903
|
* call-seq:
|
1632
|
-
*
|
1904
|
+
* context.dead? = bool
|
1633
1905
|
*
|
1634
|
-
* Returns
|
1906
|
+
* Returns +true+ if context doesn't represent a live context and is created
|
1907
|
+
* during post-mortem exception handling.
|
1635
1908
|
*/
|
1636
1909
|
static VALUE
|
1637
|
-
|
1910
|
+
context_dead(VALUE self)
|
1638
1911
|
{
|
1639
|
-
|
1640
|
-
|
1641
|
-
Data_Get_Struct(self, debug_frame_t, debug_frame);
|
1642
|
-
return rb_str_new2(debug_frame->file);
|
1643
|
-
}
|
1644
|
-
|
1645
|
-
/*
|
1646
|
-
* call-seq:
|
1647
|
-
* frame.line -> int
|
1648
|
-
*
|
1649
|
-
* Returns the line number in the file.
|
1650
|
-
*/
|
1651
|
-
static VALUE
|
1652
|
-
frame_line(VALUE self)
|
1653
|
-
{
|
1654
|
-
debug_frame_t *debug_frame;
|
1655
|
-
|
1656
|
-
Data_Get_Struct(self, debug_frame_t, debug_frame);
|
1657
|
-
return INT2FIX(debug_frame->line);
|
1658
|
-
}
|
1659
|
-
|
1660
|
-
/*
|
1661
|
-
* call-seq:
|
1662
|
-
* frame.binding -> binding
|
1663
|
-
*
|
1664
|
-
* Returns the binding captured at the moment this frame was created.
|
1665
|
-
*/
|
1666
|
-
static VALUE
|
1667
|
-
frame_binding(VALUE self)
|
1668
|
-
{
|
1669
|
-
debug_frame_t *debug_frame;
|
1670
|
-
|
1671
|
-
Data_Get_Struct(self, debug_frame_t, debug_frame);
|
1672
|
-
return debug_frame->binding;
|
1673
|
-
}
|
1912
|
+
debug_context_t *debug_context;
|
1674
1913
|
|
1675
|
-
|
1676
|
-
* call-seq:
|
1677
|
-
* frame.id -> sym
|
1678
|
-
*
|
1679
|
-
* Returns the sym of the called method.
|
1680
|
-
*/
|
1681
|
-
static VALUE
|
1682
|
-
frame_id(VALUE self)
|
1683
|
-
{
|
1684
|
-
debug_frame_t *debug_frame;
|
1914
|
+
debug_check_started();
|
1685
1915
|
|
1686
|
-
Data_Get_Struct(self,
|
1687
|
-
return
|
1916
|
+
Data_Get_Struct(self, debug_context_t, debug_context);
|
1917
|
+
return CTX_FL_TEST(debug_context, CTX_FL_DEAD) ? Qtrue : Qfalse;
|
1688
1918
|
}
|
1689
1919
|
|
1690
1920
|
/*
|
@@ -1756,8 +1986,6 @@ breakpoint_id(VALUE self)
|
|
1756
1986
|
* == Summary
|
1757
1987
|
*
|
1758
1988
|
* Debugger keeps a single instance of this class for each Ruby thread.
|
1759
|
-
* This class provides access to stack frames (see Frame class). Also it
|
1760
|
-
* gives you ability to step thought the code.
|
1761
1989
|
*/
|
1762
1990
|
static void
|
1763
1991
|
Init_context()
|
@@ -1766,32 +1994,23 @@ Init_context()
|
|
1766
1994
|
rb_define_method(cContext, "stop_next=", context_stop_next, 1);
|
1767
1995
|
rb_define_method(cContext, "step_over", context_step_over, -1);
|
1768
1996
|
rb_define_method(cContext, "stop_frame=", context_stop_frame, 1);
|
1769
|
-
rb_define_method(cContext, "frames", context_frames, 0);
|
1770
1997
|
rb_define_method(cContext, "thread", context_thread, 0);
|
1771
1998
|
rb_define_method(cContext, "thnum", context_thnum, 0);
|
1772
1999
|
rb_define_method(cContext, "suspend", context_suspend, 0);
|
2000
|
+
rb_define_method(cContext, "suspended?", context_is_suspended, 0);
|
1773
2001
|
rb_define_method(cContext, "resume", context_resume, 0);
|
1774
2002
|
rb_define_method(cContext, "tracing", context_tracing, 0);
|
1775
2003
|
rb_define_method(cContext, "tracing=", context_set_tracing, 1);
|
1776
2004
|
rb_define_method(cContext, "ignore", context_ignore, 0);
|
1777
2005
|
rb_define_method(cContext, "ignore=", context_set_ignore, 1);
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
*/
|
1787
|
-
static void
|
1788
|
-
Init_frame()
|
1789
|
-
{
|
1790
|
-
cFrame = rb_define_class_under(cContext, "Frame", rb_cObject);
|
1791
|
-
rb_define_method(cFrame, "file", frame_file, 0);
|
1792
|
-
rb_define_method(cFrame, "line", frame_line, 0);
|
1793
|
-
rb_define_method(cFrame, "binding", frame_binding, 0);
|
1794
|
-
rb_define_method(cFrame, "id", frame_id, 0);
|
2006
|
+
rb_define_method(cContext, "frame_binding", context_frame_binding, 1);
|
2007
|
+
rb_define_method(cContext, "frame_id", context_frame_id, 1);
|
2008
|
+
rb_define_method(cContext, "frame_line", context_frame_line, 1);
|
2009
|
+
rb_define_method(cContext, "frame_file", context_frame_file, 1);
|
2010
|
+
rb_define_method(cContext, "frame_locals", context_frame_locals, 1);
|
2011
|
+
rb_define_method(cContext, "frame_self", context_frame_self, 1);
|
2012
|
+
rb_define_method(cContext, "stack_size", context_stack_size, 0);
|
2013
|
+
rb_define_method(cContext, "dead?", context_dead, 0);
|
1795
2014
|
}
|
1796
2015
|
|
1797
2016
|
/*
|
@@ -1812,6 +2031,7 @@ Init_breakpoint()
|
|
1812
2031
|
rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
|
1813
2032
|
}
|
1814
2033
|
|
2034
|
+
|
1815
2035
|
/*
|
1816
2036
|
* Document-class: Debugger
|
1817
2037
|
*
|
@@ -1849,13 +2069,12 @@ Init_ruby_debug()
|
|
1849
2069
|
rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
|
1850
2070
|
rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0);
|
1851
2071
|
rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1);
|
1852
|
-
rb_define_module_function(mDebugger, "
|
1853
|
-
rb_define_module_function(mDebugger, "
|
2072
|
+
rb_define_module_function(mDebugger, "keep_frame_binding?", debug_keep_frame_binding, 0);
|
2073
|
+
rb_define_module_function(mDebugger, "keep_frame_binding=", debug_set_keep_frame_binding, 1);
|
1854
2074
|
|
1855
2075
|
cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
|
1856
2076
|
|
1857
2077
|
Init_context();
|
1858
|
-
Init_frame();
|
1859
2078
|
Init_breakpoint();
|
1860
2079
|
|
1861
2080
|
idAtLine = rb_intern("at_line");
|