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 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
@@ -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");