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 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
- 'frame_info' => false
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, implies -s option") {|options.port|}
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.keep_frame_info = options.frame_info
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.6.2"
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
- unsigned long thread_id;
44
- VALUE frames;
45
- debug_frame_t *top_frame;
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 = Qnil;
69
- static VALUE breakpoints = Qnil;
70
- static VALUE catchpoint = Qnil;
71
- static VALUE tracing = Qfalse;
72
- static VALUE locker = Qnil;
73
- static VALUE post_mortem = Qfalse;
74
- static VALUE keep_frame_info = Qfalse;
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
- unsigned long thread_id;
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 unsigned long
177
+ inline static VALUE
124
178
  ref2id(VALUE obj)
125
179
  {
126
- return NUM2ULONG(rb_obj_id(obj));
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(unsigned long id)
203
+ id2ref(VALUE id)
149
204
  {
150
- return rb_rescue(id2ref_unprotected, ULONG2NUM(id), id2ref_error, 0);
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(unsigned long thread_id)
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
- unsigned long thread_id = ref2id(thread);
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* data)
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
- rb_gc_mark(debug_context->frames);
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->frames = rb_ary_new();
341
- debug_context->top_frame = NULL;
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
- result = Data_Wrap_Struct(cContext, debug_context_mark, xfree, debug_context);
344
- return result;
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
- unsigned long thread_id;
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 frame, binding;
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
- binding = self && RTEST(keep_frame_info)? create_binding(self) : Qnil;
414
- debug_frame = ALLOC(debug_frame_t);
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
- frame = Data_Wrap_Struct(cFrame, debug_frame_mark, xfree, debug_frame);
420
-
421
- debug_context->top_frame = debug_frame;
422
- rb_ary_push(debug_context->frames, frame);
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
- VALUE frame;
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
- RARRAY(debug_context->frames)->len == debug_context->dest_frame)
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(RARRAY(debug_context->frames)->len < debug_context->dest_frame)
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(RARRAY(debug_context->frames)->len == 0)
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(RARRAY(debug_context->frames)->len == debug_context->stop_frame)
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
- rb_ary_pop(debug_context->frames);
755
- debug_context->top_frame = NULL;
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("@__debug_frames"), rb_obj_dup(debug_context->frames));
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.post_mortem? -> bool
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
- debug_keep_frame_info(VALUE self)
1380
+ debug_keep_frame_binding(VALUE self)
1279
1381
  {
1280
- return keep_frame_info;
1382
+ return keep_frame_binding;
1281
1383
  }
1282
1384
 
1283
1385
  /*
1284
1386
  * call-seq:
1285
- * Debugger.post_mortem = bool
1387
+ * Debugger.keep_frame_binding = bool
1286
1388
  *
1287
- * Setting to +true+ will make the debugger keep frame bindings.
1389
+ * Setting to +true+ will make the debugger create frame bindings.
1288
1390
  */
1289
1391
  static VALUE
1290
- debug_set_keep_frame_info(VALUE self, VALUE value)
1392
+ debug_set_keep_frame_binding(VALUE self, VALUE value)
1291
1393
  {
1292
- keep_frame_info = RTEST(value) ? Qtrue : Qfalse;
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
- rb_ary_clear(debug_context->frames);
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(RARRAY(debug_context->frames)->len == 0)
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 = RARRAY(debug_context->frames)->len;
1535
+ debug_context->dest_frame = debug_context->stack_size;
1436
1536
  }
1437
1537
  else
1438
1538
  {
1439
- if(FIX2INT(frame) < 0 && FIX2INT(frame) >= RARRAY(debug_context->frames)->len)
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 = RARRAY(debug_context->frames)->len - FIX2INT(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) >= RARRAY(debug_context->frames)->len)
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 = RARRAY(debug_context->frames)->len - FIX2INT(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.frames -> array
1681
+ * context.frame_locals(frame) -> hash
1471
1682
  *
1472
- * Returns an array of frames.
1683
+ * Returns frame's local variables.
1473
1684
  */
1474
1685
  static VALUE
1475
- context_frames(VALUE self)
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
- return debug_context->frames;
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
- * frame.file -> string
1904
+ * context.dead? = bool
1633
1905
  *
1634
- * Returns the name of the file.
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
- frame_file(VALUE self)
1910
+ context_dead(VALUE self)
1638
1911
  {
1639
- debug_frame_t *debug_frame;
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, debug_frame_t, debug_frame);
1687
- return debug_frame->id ? ID2SYM(debug_frame->id): Qnil;
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
- * Document-class: Frame
1782
- *
1783
- * == Summary
1784
- *
1785
- * This class holds infomation about a particular call frame.
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, "keep_frame_info?", debug_keep_frame_info, 0);
1853
- rb_define_module_function(mDebugger, "keep_frame_info=", debug_set_keep_frame_info, 1);
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");