ruby-debug 0.6.2-mswin32 → 0.7-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 +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
- data/lib/ruby_debug.so +0 -0
- 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");
|