ruby-debug 0.5.3 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,11 @@
1
+ 0.6
2
+ - Added option to exclude collecting of frame bindings.
3
+ - Several performance optimizations.
4
+
5
+ 0.5.4
6
+ - Added -x/--trace option to rdebug script. Patch from R. Bernstein.
7
+ - Removed a live thread reference from the context's structure avoiding memory leakage.
8
+
1
9
  0.5.3
2
10
  - Added Module#post_mortem_method method, which wraps any method with Debugger.post_mortem block.
3
11
  - Added breakpoint id, which is not dependent on the breakpoint position in Debugger.breakpoints array.
data/bin/rdebug CHANGED
@@ -14,7 +14,9 @@ options = OpenStruct.new(
14
14
  'wait' => false,
15
15
  'nostop' => false,
16
16
  'post_mortem' => false,
17
- 'script' => nil
17
+ 'script' => nil,
18
+ 'tracing' => false,
19
+ 'frame_info' => false
18
20
  )
19
21
 
20
22
  opts = OptionParser.new do |opts|
@@ -25,11 +27,13 @@ EOB
25
27
  opts.separator ""
26
28
  opts.separator "Options:"
27
29
  opts.on("-s", "--server", "Listen for remote connections") {options.server = true}
30
+ opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
31
+ opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
28
32
  opts.on("-w", "--wait", "Wait for a client connection, implies -s option") {options.wait = true}
33
+ opts.on("-x", "--trace", "turn on line tracing") {options.tracing = true}
29
34
  opts.on("-n", "--nostop", "Do not stop when a client connects, implies -s option") {options.nostop = true}
35
+ opts.on("-f", "--keep-frame-state", "Keep frame state") {options.frame_info = true}
30
36
  opts.on("-m", "--post-mortem", "Activate post-mortem mode") {options.post_mortem = true}
31
- opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
32
- opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
33
37
  opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
34
38
  opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path|
35
39
  $LOAD_PATH.unshift(path)
@@ -82,6 +86,7 @@ else
82
86
  trap('INT') { Debugger.interrupt_last }
83
87
  Debugger.stop_on_connect = !options.nostop
84
88
  Debugger.wait_connection = options.wait
89
+ Debugger.keep_frame_info = options.frame_info
85
90
  load "#{ENV["HOME"]}/.rdebugrc" if File.exists?("#{ENV["HOME"]}/.rdebugrc")
86
91
  if options.server
87
92
  Debugger.start_remote(options.host, [options.port, options.cport], options.post_mortem)
@@ -92,7 +97,11 @@ else
92
97
  Debugger.run_script(options.script)
93
98
  end
94
99
  Debugger.post_mortem if options.post_mortem
95
- debugger 2
100
+ if options.tracing
101
+ Debugger.tracing = true
102
+ else
103
+ debugger 2
104
+ end
96
105
  Debugger.debug_load Debugger::PROG_SCRIPT
97
106
  end
98
107
  end
@@ -4,7 +4,7 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.5.3"
7
+ #define DEBUG_VERSION "0.6"
8
8
 
9
9
  #define CTX_FL_MOVED (1<<1)
10
10
  #define CTX_FL_SUSPEND (1<<2)
@@ -17,11 +17,15 @@
17
17
  #define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
18
18
 
19
19
  #define DID_MOVED (debug_context->last_line != line || \
20
- debug_context->last_file == Qnil || \
21
- rb_str_cmp(debug_context->last_file, file) != 0)
20
+ debug_context->last_file == NULL || \
21
+ strcmp(debug_context->last_file, file) != 0)
22
22
 
23
23
  #define IS_STARTED (threads_tbl != Qnil)
24
24
 
25
+ #ifndef min
26
+ #define min(x,y) ((x) < (y) ? (x) : (y))
27
+ #endif
28
+
25
29
  typedef struct {
26
30
  int thnum;
27
31
  int flags;
@@ -29,23 +33,30 @@ typedef struct {
29
33
  int dest_frame;
30
34
  int stop_line;
31
35
  int stop_frame;
36
+ unsigned long thread_id;
32
37
  VALUE frames;
33
- VALUE thread;
34
- VALUE last_file;
35
- VALUE last_line;
38
+ const char * last_file;
39
+ int last_line;
36
40
  } debug_context_t;
37
41
 
38
42
  typedef struct {
39
- VALUE file;
40
- VALUE line;
41
- VALUE binding;
42
43
  ID id;
44
+ VALUE binding;
45
+ int line;
46
+ const char * file;
43
47
  } debug_frame_t;
44
48
 
49
+ enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
50
+
45
51
  typedef struct {
46
52
  int id;
53
+ int type;
47
54
  VALUE source;
48
- VALUE pos;
55
+ union
56
+ {
57
+ int line;
58
+ ID mid;
59
+ } pos;
49
60
  VALUE expr;
50
61
  } debug_breakpoint_t;
51
62
 
@@ -53,12 +64,13 @@ typedef struct {
53
64
  st_table *tbl;
54
65
  } threads_table_t;
55
66
 
56
- static VALUE threads_tbl = Qnil;
57
- static VALUE breakpoints = Qnil;
58
- static VALUE catchpoint = Qnil;
59
- static VALUE tracing = Qfalse;
60
- static VALUE locker = Qnil;
61
- static VALUE post_mortem = Qfalse;
67
+ static VALUE threads_tbl = Qnil;
68
+ static VALUE breakpoints = Qnil;
69
+ static VALUE catchpoint = Qnil;
70
+ static VALUE tracing = Qfalse;
71
+ static VALUE locker = Qnil;
72
+ static VALUE post_mortem = Qfalse;
73
+ static VALUE keep_frame_info = Qfalse;
62
74
 
63
75
  static VALUE mDebugger;
64
76
  static VALUE cThreadsTable;
@@ -66,15 +78,12 @@ static VALUE cContext;
66
78
  static VALUE cFrame;
67
79
  static VALUE cBreakpoint;
68
80
 
69
- static VALUE file_separator;
70
- static VALUE alt_file_separator;
81
+ static VALUE rb_mObjectSpace;
71
82
 
72
83
  static ID idAtLine;
73
84
  static ID idAtBreakpoint;
74
85
  static ID idAtCatchpoint;
75
86
  static ID idAtTracing;
76
- static ID idBinding;
77
- static ID idBasename;
78
87
  static ID idEval;
79
88
  static ID idList;
80
89
  static ID idClear;
@@ -84,20 +93,67 @@ static int start_count = 0;
84
93
  static int thnum_max = 0;
85
94
  static int bkp_count = 0;
86
95
  static int last_debugged_thnum = -1;
96
+ static unsigned long last_check = 0;
97
+ static unsigned long hook_count = 0;
87
98
 
88
99
  static VALUE create_binding(VALUE);
89
100
  static VALUE debug_stop(VALUE);
90
101
 
91
102
  typedef struct locked_thread_t {
92
- VALUE thread;
103
+ unsigned long thread_id;
93
104
  struct locked_thread_t *next;
94
105
  } locked_thread_t;
95
106
 
96
107
  static locked_thread_t *locked_head = NULL;
97
108
  static locked_thread_t *locked_tail = NULL;
98
109
 
110
+ inline static void *
111
+ ruby_method_ptr(VALUE class, ID meth_id)
112
+ {
113
+ NODE *body, *method;
114
+ st_lookup(RCLASS(class)->m_tbl, meth_id, (st_data_t *)&body);
115
+ method = (NODE *)body->u2.value;
116
+ return (void *)method->u1.value;
117
+ }
118
+
119
+ inline static unsigned long
120
+ ref2id(VALUE obj)
121
+ {
122
+ return NUM2ULONG(rb_obj_id(obj));
123
+ }
124
+
125
+ static VALUE
126
+ id2ref_unprotected(VALUE id)
127
+ {
128
+ typedef VALUE (*id2ref_func_t)(VALUE, VALUE);
129
+ static id2ref_func_t f_id2ref = NULL;
130
+ if(f_id2ref == NULL)
131
+ {
132
+ f_id2ref = ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref"));
133
+ }
134
+ return f_id2ref(rb_mObjectSpace, id);
135
+ }
136
+
137
+ static VALUE
138
+ id2ref_error()
139
+ {
140
+ return Qnil;
141
+ }
142
+
143
+ static VALUE
144
+ id2ref(unsigned long id)
145
+ {
146
+ return rb_rescue(id2ref_unprotected, ULONG2NUM(id), id2ref_error, 0);
147
+ }
148
+
149
+ inline static VALUE
150
+ context_thread_0(debug_context_t *debug_context)
151
+ {
152
+ return id2ref(debug_context->thread_id);
153
+ }
154
+
99
155
  static int
100
- is_in_locked(VALUE thread)
156
+ is_in_locked(unsigned long thread_id)
101
157
  {
102
158
  locked_thread_t *node;
103
159
 
@@ -106,7 +162,7 @@ is_in_locked(VALUE thread)
106
162
 
107
163
  for(node = locked_head; node != locked_tail; node = node->next)
108
164
  {
109
- if(node->thread == thread) return 1;
165
+ if(node->thread_id == thread_id) return 1;
110
166
  }
111
167
  return 0;
112
168
  }
@@ -115,12 +171,13 @@ static void
115
171
  add_to_locked(VALUE thread)
116
172
  {
117
173
  locked_thread_t *node;
174
+ unsigned long thread_id = ref2id(thread);
118
175
 
119
- if(is_in_locked(thread))
176
+ if(is_in_locked(thread_id))
120
177
  return;
121
178
 
122
179
  node = ALLOC(locked_thread_t);
123
- node->thread = thread;
180
+ node->thread_id = thread_id;
124
181
  node->next = NULL;
125
182
  if(locked_tail)
126
183
  locked_tail->next = node;
@@ -141,15 +198,15 @@ remove_from_locked()
141
198
  locked_head = locked_head->next;
142
199
  if(locked_tail == node)
143
200
  locked_tail = NULL;
144
- thread = node->thread;
201
+ thread = id2ref(node->thread_id);
145
202
  xfree(node);
146
203
  return thread;
147
204
  }
148
205
 
149
206
  static int
150
- thread_hash(VALUE thread)
207
+ thread_hash(unsigned long thread_id)
151
208
  {
152
- return (int)FIX2LONG(rb_obj_id(thread));
209
+ return (int)thread_id;
153
210
  }
154
211
 
155
212
  static int
@@ -168,7 +225,6 @@ static struct st_hash_type st_thread_hash = {
168
225
  static int
169
226
  threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy)
170
227
  {
171
- rb_gc_mark(key);
172
228
  rb_gc_mark(value);
173
229
  return ST_CONTINUE;
174
230
  }
@@ -213,6 +269,43 @@ threads_table_clear(VALUE table)
213
269
  st_foreach(threads_table->tbl, threads_table_clear_i, 0);
214
270
  }
215
271
 
272
+ static VALUE
273
+ is_thread_alive(VALUE thread)
274
+ {
275
+ static ID id_alive = 0;
276
+ if(!id_alive)
277
+ {
278
+ id_alive = rb_intern("alive?");
279
+ }
280
+ return rb_funcall(thread, id_alive, 0);
281
+ }
282
+
283
+ static int
284
+ threads_table_check_i(VALUE key, VALUE value, VALUE dummy)
285
+ {
286
+ VALUE thread;
287
+
288
+ thread = id2ref(key);
289
+ if(!rb_obj_is_kind_of(thread, rb_cThread))
290
+ {
291
+ return ST_DELETE;
292
+ }
293
+ if(rb_protect(is_thread_alive, thread, 0) != Qtrue)
294
+ {
295
+ return ST_DELETE;
296
+ }
297
+ return ST_CONTINUE;
298
+ }
299
+
300
+ static void
301
+ check_thread_contexts()
302
+ {
303
+ threads_table_t *threads_table;
304
+
305
+ Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
306
+ st_foreach(threads_table->tbl, threads_table_check_i, 0);
307
+ }
308
+
216
309
  /*
217
310
  * call-seq:
218
311
  * Debugger.started? -> bool
@@ -239,9 +332,6 @@ debug_context_mark(void* data)
239
332
  {
240
333
  debug_context_t *debug_context = (debug_context_t *)data;
241
334
  rb_gc_mark(debug_context->frames);
242
- rb_gc_mark(debug_context->thread);
243
- rb_gc_mark(debug_context->last_file);
244
- rb_gc_mark(debug_context->last_line);
245
335
  }
246
336
 
247
337
  static VALUE
@@ -253,8 +343,8 @@ debug_context_create(VALUE thread)
253
343
  debug_context = ALLOC(debug_context_t);
254
344
  debug_context-> thnum = ++thnum_max;
255
345
 
256
- debug_context->last_file = Qnil;
257
- debug_context->last_line = Qnil;
346
+ debug_context->last_file = NULL;
347
+ debug_context->last_line = 0;
258
348
  debug_context->flags = 0;
259
349
 
260
350
  debug_context->stop_next = -1;
@@ -262,7 +352,7 @@ debug_context_create(VALUE thread)
262
352
  debug_context->stop_line = -1;
263
353
  debug_context->stop_frame = -1;
264
354
  debug_context->frames = rb_ary_new();
265
- debug_context->thread = thread;
355
+ debug_context->thread_id = ref2id(thread);
266
356
  result = Data_Wrap_Struct(cContext, debug_context_mark, xfree, debug_context);
267
357
  return result;
268
358
  }
@@ -272,14 +362,15 @@ thread_context_lookup(VALUE thread)
272
362
  {
273
363
  VALUE context;
274
364
  threads_table_t *threads_table;
365
+ unsigned long thread_id = ref2id(thread);
275
366
 
276
367
  debug_check_started();
277
368
 
278
369
  Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
279
- if(!st_lookup(threads_table->tbl, thread, &context))
370
+ if(!st_lookup(threads_table->tbl, thread_id, &context))
280
371
  {
281
372
  context = debug_context_create(thread);
282
- st_insert(threads_table->tbl, thread, context);
373
+ st_insert(threads_table->tbl, thread_id, context);
283
374
  }
284
375
  return context;
285
376
  }
@@ -289,12 +380,10 @@ debug_frame_mark(void *data)
289
380
  {
290
381
  debug_frame_t *debug_frame = (debug_frame_t *)data;
291
382
  rb_gc_mark(debug_frame->binding);
292
- rb_gc_mark(debug_frame->file);
293
- rb_gc_mark(debug_frame->line);
294
383
  }
295
384
 
296
385
  static VALUE
297
- debug_frame_create(VALUE file, VALUE line, VALUE binding, ID id)
386
+ debug_frame_create(char *file, int line, VALUE binding, ID id)
298
387
  {
299
388
  VALUE result;
300
389
  debug_frame_t *debug_frame;
@@ -337,89 +426,112 @@ call_at_line_unprotected(VALUE args)
337
426
  }
338
427
 
339
428
  static VALUE
340
- call_at_line(VALUE context, int thnum, VALUE binding, VALUE file, VALUE line)
429
+ call_at_line(VALUE context, int thnum, VALUE file, VALUE line)
341
430
  {
342
431
  VALUE args;
343
432
 
344
433
  last_debugged_thnum = thnum;
345
434
  save_current_position(context);
346
435
 
347
- args = rb_ary_new3(4, context, file, line, binding);
436
+ args = rb_ary_new3(3, context, file, line);
348
437
  return rb_protect(call_at_line_unprotected, args, 0);
349
438
  }
350
439
 
351
440
  static void
352
- set_frame_source(debug_context_t *debug_context, VALUE file, VALUE line)
353
- {
354
- VALUE frame;
355
- debug_frame_t *top_frame;
356
-
357
- if(RARRAY(debug_context->frames)->len > 0)
358
- {
359
- frame = *RARRAY(debug_context->frames)->ptr;
360
- Data_Get_Struct(frame, debug_frame_t, top_frame);
361
- top_frame->file = file;
362
- top_frame->line = line;
363
- }
364
- }
365
-
366
- static void
367
- save_call_frame(VALUE self, VALUE file, VALUE line, ID mid, debug_context_t *debug_context)
441
+ save_call_frame(VALUE self, char *file, int line, ID mid, debug_context_t *debug_context)
368
442
  {
369
443
  VALUE frame, binding;
370
444
 
371
- binding = self? create_binding(self) : Qnil;
445
+ binding = self && RTEST(keep_frame_info)? create_binding(self) : Qnil;
372
446
  frame = debug_frame_create(file, line, binding, mid);
373
447
  rb_ary_unshift(debug_context->frames, frame);
374
448
  }
375
449
 
376
- static VALUE
377
- basename(VALUE filename)
450
+ #if defined DOSISH
451
+ #define isdirsep(x) ((x) == '/' || (x) == '\\')
452
+ #else
453
+ #define isdirsep(x) ((x) == '/')
454
+ #endif
455
+
456
+ static int
457
+ filename_cmp(VALUE source, char *file)
378
458
  {
379
- return rb_funcall(rb_cFile, idBasename, 1, filename);
459
+ char *source_ptr, *file_ptr;
460
+ int s_len, f_len, min_len;
461
+ int s,f;
462
+ int dirsep_flag = 0;
463
+
464
+ s_len = RSTRING(source)->len;
465
+ f_len = strlen(file);
466
+ min_len = min(s_len, f_len);
467
+
468
+ source_ptr = RSTRING(source)->ptr;
469
+ file_ptr = file;
470
+
471
+ for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- )
472
+ {
473
+ if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
474
+ return 1;
475
+ if(source_ptr[s] != file_ptr[f])
476
+ return 0;
477
+ if(isdirsep(source_ptr[s]))
478
+ dirsep_flag = 1;
479
+ }
480
+ return 1;
380
481
  }
381
482
 
382
483
  static int
383
- filename_cmp(debug_breakpoint_t *debug_breakpoint, VALUE file)
484
+ check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
384
485
  {
385
- VALUE flag = Qnil;
486
+ VALUE breakpoint;
487
+ debug_breakpoint_t *debug_breakpoint;
488
+ int i;
489
+
490
+ if(RARRAY(breakpoints)->len == 0)
491
+ return -1;
492
+ if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
493
+ return -1;
386
494
 
387
- flag = rb_funcall(debug_breakpoint->source, idIndex, 1, file_separator);
388
- if(alt_file_separator != Qnil && flag == Qnil)
389
- flag = rb_funcall(debug_breakpoint->source, idIndex, 1, alt_file_separator);
390
- if(flag == Qnil)
391
- file = basename(file);
392
- else
393
- file = rb_file_expand_path(file, Qnil);
394
- return(rb_str_cmp(debug_breakpoint->source, file) == 0);
495
+ for(i = 0; i < RARRAY(breakpoints)->len; i++)
496
+ {
497
+ breakpoint = rb_ary_entry(breakpoints, i);
498
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
499
+ if(debug_breakpoint->type != BP_POS_TYPE)
500
+ continue;
501
+ if(debug_breakpoint->pos.line != line)
502
+ continue;
503
+ if(filename_cmp(debug_breakpoint->source, file))
504
+ return i;
505
+ }
506
+ return -1;
395
507
  }
396
508
 
397
- static int
398
- classname_cmp(debug_breakpoint_t *debug_breakpoint, VALUE klass)
509
+ inline static int
510
+ classname_cmp(VALUE name, VALUE klass)
399
511
  {
400
- return (klass != Qnil && rb_str_cmp(debug_breakpoint->source, rb_mod_name(klass)) == 0);
512
+ return (klass != Qnil && rb_str_cmp(name, rb_mod_name(klass)) == 0);
401
513
  }
402
514
 
403
515
  static int
404
- check_breakpoints(debug_context_t *debug_context, VALUE file, VALUE klass, VALUE pos)
516
+ check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid)
405
517
  {
406
518
  VALUE breakpoint;
407
519
  debug_breakpoint_t *debug_breakpoint;
408
520
  int i;
409
-
521
+
410
522
  if(RARRAY(breakpoints)->len == 0)
411
523
  return -1;
412
524
  if(!CTX_FL_TEST(debug_context, CTX_FL_MOVED))
413
525
  return -1;
414
-
415
526
  for(i = 0; i < RARRAY(breakpoints)->len; i++)
416
527
  {
417
528
  breakpoint = rb_ary_entry(breakpoints, i);
418
529
  Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
419
- if(debug_breakpoint->pos != pos && !(TYPE(pos) == T_STRING &&
420
- TYPE(debug_breakpoint->pos) == T_STRING && rb_str_cmp(debug_breakpoint->pos, pos) == 0))
530
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
421
531
  continue;
422
- if(filename_cmp(debug_breakpoint, file) || classname_cmp(debug_breakpoint, klass))
532
+ if(debug_breakpoint->pos.mid != mid)
533
+ continue;
534
+ if(classname_cmp(debug_breakpoint->source, klass))
423
535
  return i;
424
536
  }
425
537
  return -1;
@@ -437,10 +549,7 @@ create_binding(VALUE self)
437
549
 
438
550
  if(f_binding == NULL)
439
551
  {
440
- NODE *body, *method;
441
- st_lookup(RCLASS(rb_mKernel)->m_tbl, idBinding, (st_data_t *)&body);
442
- method = (NODE *)body->u2.value;
443
- f_binding = (bind_func_t)method->u1.value;
552
+ f_binding = (bind_func_t)ruby_method_ptr(rb_mKernel, rb_intern("binding"));
444
553
  }
445
554
  return f_binding(self);
446
555
  }
@@ -457,7 +566,7 @@ eval_expression(VALUE args)
457
566
  return rb_funcall2(rb_mKernel, idEval, 2, RARRAY(args)->ptr);
458
567
  }
459
568
 
460
- static int
569
+ inline static int
461
570
  check_breakpoint_expression(VALUE breakpoint, VALUE binding)
462
571
  {
463
572
  debug_breakpoint_t *debug_breakpoint;
@@ -472,15 +581,53 @@ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
472
581
  return RTEST(expr_result);
473
582
  }
474
583
 
584
+ inline static debug_frame_t *
585
+ get_top_frame(debug_context_t *debug_context)
586
+ {
587
+ VALUE frame;
588
+ debug_frame_t *debug_frame;
589
+ if(RARRAY(debug_context->frames)->len == 0)
590
+ return NULL;
591
+ else {
592
+ frame = RARRAY(debug_context->frames)->ptr[0];
593
+ Data_Get_Struct(frame, debug_frame_t, debug_frame);
594
+ return debug_frame;
595
+ }
596
+ }
597
+
598
+ inline static void
599
+ save_top_binding(debug_context_t *debug_context, VALUE binding)
600
+ {
601
+ debug_frame_t *debug_frame;
602
+ debug_frame = get_top_frame(debug_context);
603
+ if(debug_frame)
604
+ debug_frame->binding = binding;
605
+ }
606
+
607
+ static void
608
+ set_frame_source(debug_context_t *debug_context, char *file, int line)
609
+ {
610
+ debug_frame_t *top_frame;
611
+ top_frame = get_top_frame(debug_context);
612
+ if(top_frame)
613
+ {
614
+ top_frame->file = file;
615
+ top_frame->line = line;
616
+ }
617
+ }
618
+
475
619
  static void
476
620
  debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
477
621
  {
478
622
  VALUE thread, context, breakpoint;
479
623
  VALUE binding = Qnil;
480
624
  debug_context_t *debug_context;
481
- VALUE file = Qnil, line = Qnil;
625
+ char *file;
626
+ int line;
482
627
  int breakpoint_index = -1;
483
628
 
629
+ hook_count++;
630
+
484
631
  if (mid == ID_ALLOCATOR) return;
485
632
  if(!node) return;
486
633
 
@@ -519,8 +666,8 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
519
666
  /* ignore a skipped section of code */
520
667
  if(CTX_FL_TEST(debug_context, CTX_FL_SKIPPED)) goto cleanup;
521
668
 
522
- file = rb_str_new2(node->nd_file);
523
- line = INT2FIX(nd_line(node));
669
+ file = node->nd_file;
670
+ line = nd_line(node);
524
671
 
525
672
  if(DID_MOVED)
526
673
  CTX_FL_SET(debug_context, CTX_FL_MOVED);
@@ -533,7 +680,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
533
680
 
534
681
  if(RTEST(tracing) || CTX_FL_TEST(debug_context, CTX_FL_TRACING))
535
682
  {
536
- rb_funcall(context, idAtTracing, 2, file, line);
683
+ rb_funcall(context, idAtTracing, 2, rb_str_new2(file), INT2FIX(line));
537
684
  }
538
685
 
539
686
  if(debug_context->dest_frame == -1 ||
@@ -559,7 +706,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
559
706
  }
560
707
 
561
708
  if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
562
- (breakpoint_index = check_breakpoints(debug_context, file, klass, line)) != -1)
709
+ (breakpoint_index = check_breakpoints_by_pos(debug_context, file, line)) != -1)
563
710
  {
564
711
  binding = self? create_binding(self) : Qnil;
565
712
  /* check breakpoint expression */
@@ -579,7 +726,8 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
579
726
  debug_context->stop_line = -1;
580
727
  debug_context->stop_next = -1;
581
728
 
582
- call_at_line(context, debug_context->thnum, binding, file, line);
729
+ save_top_binding(debug_context, binding);
730
+ call_at_line(context, debug_context->thnum, rb_str_new2(file), INT2FIX(line));
583
731
  }
584
732
  break;
585
733
  }
@@ -591,15 +739,21 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
591
739
  case RUBY_EVENT_CALL:
592
740
  {
593
741
  save_call_frame(self, file, line, mid, debug_context);
594
- breakpoint_index = check_breakpoints(debug_context, file, klass, rb_str_new2(rb_id2name(mid)));
742
+ breakpoint_index = check_breakpoints_by_method(debug_context, klass, mid);
595
743
  if(breakpoint_index != -1)
596
744
  {
597
- binding = self? create_binding(self) : Qnil;
745
+ debug_frame_t *debug_frame;
746
+ debug_frame = get_top_frame(debug_context);
747
+ if(debug_frame)
748
+ binding = debug_frame->binding;
749
+ if(NIL_P(binding) && self)
750
+ binding = create_binding(self);
598
751
  breakpoint = get_breakpoint_at(breakpoint_index);
599
752
  if(check_breakpoint_expression(breakpoint, binding))
600
753
  {
754
+ save_top_binding(debug_context, binding);
601
755
  rb_funcall(context, idAtBreakpoint, 1, breakpoint);
602
- call_at_line(context, debug_context->thnum, binding, file, line);
756
+ call_at_line(context, debug_context->thnum, rb_str_new2(file), INT2FIX(line));
603
757
  }
604
758
  }
605
759
  break;
@@ -629,8 +783,8 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
629
783
  if(post_mortem == Qtrue && self)
630
784
  {
631
785
  binding = create_binding(self);
632
- rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), file);
633
- rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), line);
786
+ rb_ivar_set(ruby_errinfo, rb_intern("@__debug_file"), rb_str_new2(file));
787
+ rb_ivar_set(ruby_errinfo, rb_intern("@__debug_line"), INT2FIX(line));
634
788
  rb_ivar_set(ruby_errinfo, rb_intern("@__debug_binding"), binding);
635
789
  rb_ivar_set(ruby_errinfo, rb_intern("@__debug_frames"), rb_obj_dup(debug_context->frames));
636
790
  }
@@ -654,7 +808,8 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
654
808
  rb_funcall(context, idAtCatchpoint, 1, ruby_errinfo);
655
809
  if(self && binding == Qnil)
656
810
  binding = create_binding(self);
657
- call_at_line(context, debug_context->thnum, binding, file, line);
811
+ save_top_binding(debug_context, binding);
812
+ call_at_line(context, debug_context->thnum, rb_str_new2(file), INT2FIX(line));
658
813
  break;
659
814
  }
660
815
  }
@@ -669,6 +824,13 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
669
824
 
670
825
  cleanup:
671
826
 
827
+ /* check that all contexts point to alive threads */
828
+ if(hook_count - last_check > 1000)
829
+ {
830
+ check_thread_contexts();
831
+ last_check = hook_count;
832
+ }
833
+
672
834
  /* release a lock */
673
835
  locker = Qnil;
674
836
  /* let the next thread to run */
@@ -755,7 +917,6 @@ breakpoint_mark(void *data)
755
917
  debug_breakpoint_t *breakpoint;
756
918
  breakpoint = (debug_breakpoint_t *)data;
757
919
  rb_gc_mark(breakpoint->source);
758
- rb_gc_mark(breakpoint->pos);
759
920
  rb_gc_mark(breakpoint->expr);
760
921
  }
761
922
 
@@ -775,6 +936,7 @@ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
775
936
  VALUE source, pos, expr;
776
937
  VALUE result;
777
938
  debug_breakpoint_t *breakpoint;
939
+ int type;
778
940
 
779
941
  debug_check_started();
780
942
 
@@ -782,11 +944,19 @@ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
782
944
  {
783
945
  expr = Qnil;
784
946
  }
785
-
947
+ type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
948
+ if(type == BP_POS_TYPE)
949
+ source = StringValue(source);
950
+ else
951
+ pos = StringValue(pos);
786
952
  breakpoint = ALLOC(debug_breakpoint_t);
787
- breakpoint->source = StringValue(source);
788
953
  breakpoint->id = ++bkp_count;
789
- breakpoint->pos = pos;
954
+ breakpoint->source = source;
955
+ breakpoint->type = type;
956
+ if(type == BP_POS_TYPE)
957
+ breakpoint->pos.line = FIX2INT(pos);
958
+ else
959
+ breakpoint->pos.mid = rb_intern(RSTRING(pos)->ptr);
790
960
  breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
791
961
  result = Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
792
962
  rb_ary_push(breakpoints, result);
@@ -958,7 +1128,7 @@ debug_contexts(VALUE self)
958
1128
  {
959
1129
  context = rb_ary_entry(new_list, i);
960
1130
  Data_Get_Struct(context, debug_context_t, debug_context);
961
- st_insert(threads_table->tbl, debug_context->thread, context);
1131
+ st_insert(threads_table->tbl, debug_context->thread_id, context);
962
1132
  }
963
1133
 
964
1134
  return new_list;
@@ -1033,7 +1203,7 @@ debug_resume(VALUE self)
1033
1203
  if(CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
1034
1204
  {
1035
1205
  CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND);
1036
- rb_thread_run(debug_context->thread);
1206
+ rb_thread_run(context_thread_0(debug_context));
1037
1207
  }
1038
1208
  }
1039
1209
  rb_thread_critical = saved_crit;
@@ -1096,6 +1266,31 @@ debug_set_post_mortem(VALUE self, VALUE value)
1096
1266
  return value;
1097
1267
  }
1098
1268
 
1269
+ /*
1270
+ * call-seq:
1271
+ * Debugger.post_mortem? -> bool
1272
+ *
1273
+ * Returns +true+ if the debugger will collect frame bindings.
1274
+ */
1275
+ static VALUE
1276
+ debug_keep_frame_info(VALUE self)
1277
+ {
1278
+ return keep_frame_info;
1279
+ }
1280
+
1281
+ /*
1282
+ * call-seq:
1283
+ * Debugger.post_mortem = bool
1284
+ *
1285
+ * Setting to +true+ will make the debugger keep frame bindings.
1286
+ */
1287
+ static VALUE
1288
+ debug_set_keep_frame_info(VALUE self, VALUE value)
1289
+ {
1290
+ keep_frame_info = RTEST(value) ? Qtrue : Qfalse;
1291
+ return value;
1292
+ }
1293
+
1099
1294
  /*
1100
1295
  * call-seq:
1101
1296
  * Debugger.debug_load(file) -> nil
@@ -1295,7 +1490,7 @@ context_thread(VALUE self)
1295
1490
  debug_context_t *debug_context;
1296
1491
 
1297
1492
  Data_Get_Struct(self, debug_context_t, debug_context);
1298
- return debug_context->thread;
1493
+ return context_thread_0(debug_context);
1299
1494
  }
1300
1495
 
1301
1496
  /*
@@ -1350,7 +1545,7 @@ context_resume(VALUE self)
1350
1545
  if(!CTX_FL_TEST(debug_context, CTX_FL_SUSPEND))
1351
1546
  rb_raise(rb_eRuntimeError, "Thread is not suspended.");
1352
1547
  CTX_FL_UNSET(debug_context, CTX_FL_SUSPEND);
1353
- rb_thread_run(debug_context->thread);
1548
+ rb_thread_run(context_thread_0(debug_context));
1354
1549
  return Qnil;
1355
1550
  }
1356
1551
 
@@ -1442,7 +1637,7 @@ frame_file(VALUE self)
1442
1637
  debug_frame_t *debug_frame;
1443
1638
 
1444
1639
  Data_Get_Struct(self, debug_frame_t, debug_frame);
1445
- return debug_frame->file;
1640
+ return rb_str_new2(debug_frame->file);
1446
1641
  }
1447
1642
 
1448
1643
  /*
@@ -1457,7 +1652,7 @@ frame_line(VALUE self)
1457
1652
  debug_frame_t *debug_frame;
1458
1653
 
1459
1654
  Data_Get_Struct(self, debug_frame_t, debug_frame);
1460
- return debug_frame->line;
1655
+ return INT2FIX(debug_frame->line);
1461
1656
  }
1462
1657
 
1463
1658
  /*
@@ -1517,7 +1712,10 @@ breakpoint_pos(VALUE self)
1517
1712
  debug_breakpoint_t *breakpoint;
1518
1713
 
1519
1714
  Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
1520
- return breakpoint->pos;
1715
+ if(breakpoint->type == BP_METHOD_TYPE)
1716
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
1717
+ else
1718
+ return INT2FIX(breakpoint->pos.line);
1521
1719
  }
1522
1720
 
1523
1721
  /*
@@ -1648,6 +1846,8 @@ Init_ruby_debug()
1648
1846
  rb_define_module_function(mDebugger, "debug_at_exit", debug_at_exit, 0);
1649
1847
  rb_define_module_function(mDebugger, "post_mortem?", debug_post_mortem, 0);
1650
1848
  rb_define_module_function(mDebugger, "post_mortem=", debug_set_post_mortem, 1);
1849
+ rb_define_module_function(mDebugger, "keep_frame_info?", debug_keep_frame_info, 0);
1850
+ rb_define_module_function(mDebugger, "keep_frame_info=", debug_set_keep_frame_info, 1);
1651
1851
 
1652
1852
  cThreadsTable = rb_define_class_under(mDebugger, "ThreadsTable", rb_cObject);
1653
1853
 
@@ -1659,20 +1859,15 @@ Init_ruby_debug()
1659
1859
  idAtBreakpoint = rb_intern("at_breakpoint");
1660
1860
  idAtCatchpoint = rb_intern("at_catchpoint");
1661
1861
  idAtTracing = rb_intern("at_tracing");
1662
- idBinding = rb_intern("binding");
1663
- idBasename = rb_intern("basename");
1664
1862
  idEval = rb_intern("eval");
1665
1863
  idList = rb_intern("list");
1666
1864
  idClear = rb_intern("clear");
1667
1865
  idIndex = rb_intern("index");
1668
1866
 
1669
- file_separator = rb_eval_string("File::SEPARATOR");
1670
- alt_file_separator = rb_eval_string("File::ALT_SEPARATOR");
1867
+ rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace"));
1671
1868
 
1672
1869
  rb_global_variable(&threads_tbl);
1673
1870
  rb_global_variable(&breakpoints);
1674
1871
  rb_global_variable(&catchpoint);
1675
1872
  rb_global_variable(&locker);
1676
- rb_global_variable(&file_separator);
1677
- rb_global_variable(&alt_file_separator);
1678
1873
  }
@@ -0,0 +1,90 @@
1
+ CTX_FL_SET ruby_debug.c /^#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } /
2
+ CTX_FL_TEST ruby_debug.c /^#define CTX_FL_TEST(c,f) ((c)->flags & (f))$/
3
+ CTX_FL_UNSET ruby_debug.c /^#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f);/
4
+ Init_breakpoint ruby_debug.c /^Init_breakpoint()$/
5
+ Init_context ruby_debug.c /^Init_context()$/
6
+ Init_frame ruby_debug.c /^Init_frame()$/
7
+ Init_ruby_debug ruby_debug.c /^Init_ruby_debug()$/
8
+ VALUE ruby_debug.c /^ typedef VALUE (*bind_func_t)(VALUE);$/
9
+ add_to_locked ruby_debug.c /^add_to_locked(VALUE thread)$/
10
+ basename ruby_debug.c /^basename(VALUE filename)$/
11
+ breakpoint_expr ruby_debug.c /^breakpoint_expr(VALUE self)$/
12
+ breakpoint_id ruby_debug.c /^breakpoint_id(VALUE self)$/
13
+ breakpoint_mark ruby_debug.c /^breakpoint_mark(void *data)$/
14
+ breakpoint_pos ruby_debug.c /^breakpoint_pos(VALUE self)$/
15
+ breakpoint_source ruby_debug.c /^breakpoint_source(VALUE self)$/
16
+ call_at_line ruby_debug.c /^call_at_line(VALUE context, int thnum, VALUE bindi/
17
+ call_at_line_unprotected ruby_debug.c /^call_at_line_unprotected(VALUE args)$/
18
+ check_breakpoint_expression ruby_debug.c /^check_breakpoint_expression(VALUE breakpoint, VALU/
19
+ check_breakpoints ruby_debug.c /^check_breakpoints(debug_context_t *debug_context, /
20
+ classname_cmp ruby_debug.c /^classname_cmp(debug_breakpoint_t *debug_breakpoint/
21
+ context_frames ruby_debug.c /^context_frames(VALUE self)$/
22
+ context_ignore ruby_debug.c /^context_ignore(VALUE self)$/
23
+ context_resume ruby_debug.c /^context_resume(VALUE self)$/
24
+ context_set_ignore ruby_debug.c /^context_set_ignore(VALUE self, VALUE value)$/
25
+ context_set_tracing ruby_debug.c /^context_set_tracing(VALUE self, VALUE value)$/
26
+ context_step_over ruby_debug.c /^context_step_over(int argc, VALUE *argv, VALUE sel/
27
+ context_stop_frame ruby_debug.c /^context_stop_frame(VALUE self, VALUE frame)$/
28
+ context_stop_next ruby_debug.c /^context_stop_next(VALUE self, VALUE steps)$/
29
+ context_suspend ruby_debug.c /^context_suspend(VALUE self)$/
30
+ context_thnum ruby_debug.c /^context_thnum(VALUE self)$/
31
+ context_thread ruby_debug.c /^context_thread(VALUE self)$/
32
+ context_tracing ruby_debug.c /^context_tracing(VALUE self)$/
33
+ create_binding ruby_debug.c /^create_binding(VALUE self)$/
34
+ debug_add_breakpoint ruby_debug.c /^debug_add_breakpoint(int argc, VALUE *argv, VALUE /
35
+ debug_at_exit ruby_debug.c /^debug_at_exit(VALUE self)$/
36
+ debug_at_exit_c ruby_debug.c /^debug_at_exit_c(VALUE proc)$/
37
+ debug_at_exit_i ruby_debug.c /^debug_at_exit_i(VALUE proc)$/
38
+ debug_breakpoint_t ruby_debug.c /^} debug_breakpoint_t;$/
39
+ debug_breakpoints ruby_debug.c /^debug_breakpoints(VALUE self)$/
40
+ debug_catchpoint ruby_debug.c /^debug_catchpoint(VALUE self)$/
41
+ debug_check_started ruby_debug.c /^debug_check_started()$/
42
+ debug_context_create ruby_debug.c /^debug_context_create(VALUE thread)$/
43
+ debug_context_mark ruby_debug.c /^debug_context_mark(void* data)$/
44
+ debug_context_t ruby_debug.c /^} debug_context_t;$/
45
+ debug_contexts ruby_debug.c /^debug_contexts(VALUE self)$/
46
+ debug_current_context ruby_debug.c /^debug_current_context(VALUE self)$/
47
+ debug_debug_load ruby_debug.c /^debug_debug_load(VALUE self, VALUE file)$/
48
+ debug_event_hook ruby_debug.c /^debug_event_hook(rb_event_t event, NODE *node, VAL/
49
+ debug_frame_create ruby_debug.c /^debug_frame_create(VALUE file, VALUE line, VALUE b/
50
+ debug_frame_mark ruby_debug.c /^debug_frame_mark(void *data)$/
51
+ debug_frame_t ruby_debug.c /^} debug_frame_t;$/
52
+ debug_is_started ruby_debug.c /^debug_is_started(VALUE self)$/
53
+ debug_last_interrupted ruby_debug.c /^debug_last_interrupted(VALUE self)$/
54
+ debug_post_mortem ruby_debug.c /^debug_post_mortem(VALUE self)$/
55
+ debug_remove_breakpoint ruby_debug.c /^debug_remove_breakpoint(VALUE self, VALUE id_value/
56
+ debug_resume ruby_debug.c /^debug_resume(VALUE self)$/
57
+ debug_set_catchpoint ruby_debug.c /^debug_set_catchpoint(VALUE self, VALUE value)$/
58
+ debug_set_post_mortem ruby_debug.c /^debug_set_post_mortem(VALUE self, VALUE value)$/
59
+ debug_set_tracing ruby_debug.c /^debug_set_tracing(VALUE self, VALUE value)$/
60
+ debug_skip ruby_debug.c /^debug_skip(VALUE self)$/
61
+ debug_start ruby_debug.c /^debug_start(VALUE self)$/
62
+ debug_stop ruby_debug.c /^debug_stop(VALUE self)$/
63
+ debug_stop_i ruby_debug.c /^debug_stop_i(VALUE self)$/
64
+ debug_suspend ruby_debug.c /^debug_suspend(VALUE self)$/
65
+ debug_tracing ruby_debug.c /^debug_tracing(VALUE self)$/
66
+ eval_expression ruby_debug.c /^eval_expression(VALUE args)$/
67
+ filename_cmp ruby_debug.c /^filename_cmp(debug_breakpoint_t *debug_breakpoint,/
68
+ find_last_context_func ruby_debug.c /^find_last_context_func(VALUE key, VALUE value, VAL/
69
+ frame_binding ruby_debug.c /^frame_binding(VALUE self)$/
70
+ frame_file ruby_debug.c /^frame_file(VALUE self)$/
71
+ frame_id ruby_debug.c /^frame_id(VALUE self)$/
72
+ frame_line ruby_debug.c /^frame_line(VALUE self)$/
73
+ get_breakpoint_at ruby_debug.c /^get_breakpoint_at(int index) $/
74
+ is_in_locked ruby_debug.c /^is_in_locked(VALUE thread)$/
75
+ locked_thread_t ruby_debug.c /^} locked_thread_t;$/
76
+ remove_from_locked ruby_debug.c /^remove_from_locked()$/
77
+ save_call_frame ruby_debug.c /^save_call_frame(VALUE self, VALUE file, VALUE line/
78
+ save_current_position ruby_debug.c /^save_current_position(VALUE context)$/
79
+ set_current_skipped_status ruby_debug.c /^set_current_skipped_status(VALUE status)$/
80
+ set_frame_source ruby_debug.c /^set_frame_source(debug_context_t *debug_context, V/
81
+ thread_cmp ruby_debug.c /^thread_cmp(VALUE a, VALUE b)$/
82
+ thread_context_lookup ruby_debug.c /^thread_context_lookup(VALUE thread)$/
83
+ thread_hash ruby_debug.c /^thread_hash(VALUE thread)$/
84
+ threads_table_clear ruby_debug.c /^threads_table_clear(VALUE table)$/
85
+ threads_table_clear_i ruby_debug.c /^threads_table_clear_i(VALUE key, VALUE value, VALU/
86
+ threads_table_create ruby_debug.c /^threads_table_create()$/
87
+ threads_table_free ruby_debug.c /^threads_table_free(void* data)$/
88
+ threads_table_mark ruby_debug.c /^threads_table_mark(void* data)$/
89
+ threads_table_mark_keyvalue ruby_debug.c /^threads_table_mark_keyvalue(VALUE key, VALUE value/
90
+ threads_table_t ruby_debug.c /^} threads_table_t;$/
@@ -36,8 +36,8 @@ module Debugger
36
36
  processor.at_tracing(self, file, line)
37
37
  end
38
38
 
39
- def at_line(file, line, binding)
40
- processor.at_line(self, file, line, binding)
39
+ def at_line(file, line)
40
+ processor.at_line(self, file, line)
41
41
  end
42
42
  end
43
43
 
@@ -170,7 +170,7 @@ module Debugger
170
170
  private :stop_main_thread
171
171
 
172
172
  def source_for(file) # :nodoc:
173
- Dir.chdir File.dirname($0) do
173
+ finder = lambda do
174
174
  unless File.exists?(file)
175
175
  return (SCRIPT_LINES__[file] == true ? nil : SCRIPT_LINES__[file])
176
176
  end
@@ -187,6 +187,7 @@ module Debugger
187
187
 
188
188
  SCRIPT_LINES__[file]
189
189
  end
190
+ Dir.chdir(File.dirname($0)){finder.call} || finder.call
190
191
  end
191
192
 
192
193
  def source_reload
@@ -257,7 +258,11 @@ module Debugger
257
258
 
258
259
  def handle_post_mortem(exp)
259
260
  return if exp.__debug_frames.empty?
260
- processor.at_line(nil, exp.__debug_file, exp.__debug_line, exp.__debug_frames.first.binding, exp.__debug_frames)
261
+ orig_tracing = Debugger.tracing, Debugger.current_context.tracing
262
+ Debugger.tracing = Debugger.current_context.tracing = false
263
+ processor.at_line(nil, exp.__debug_file, exp.__debug_line, exp.__debug_frames)
264
+ ensure
265
+ Debugger.tracing, Debugger.current_context.tracing = orig_tracing
261
266
  end
262
267
  private :handle_post_mortem
263
268
  end
@@ -62,11 +62,15 @@ module Debugger
62
62
  @state.confirm(msg) == 'y'
63
63
  end
64
64
 
65
- def debug_eval(str)
65
+ def debug_eval(str, b = @state.binding)
66
+ unless b
67
+ print "Can't evaluate in the current context.\n"
68
+ throw :debug_error
69
+ end
66
70
  begin
67
- val = eval(str, @state.binding)
71
+ val = eval(str, b)
68
72
  rescue StandardError, ScriptError => e
69
- at = eval("caller(1)", @state.binding)
73
+ at = eval("caller(1)", b)
70
74
  print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
71
75
  for i in at
72
76
  print "\tfrom %s\n", i
@@ -76,6 +80,7 @@ module Debugger
76
80
  end
77
81
 
78
82
  def debug_silent_eval(str)
83
+ return nil unless @state.binding
79
84
  begin
80
85
  eval(str, @state.binding)
81
86
  rescue StandardError, ScriptError
@@ -35,7 +35,11 @@ module Debugger
35
35
  def execute
36
36
  unless @state.interface.kind_of?(LocalInterface)
37
37
  print "Command is available only in local mode.\n"
38
- return
38
+ throw :debug_error
39
+ end
40
+ unless @state.binding
41
+ print "Can't evaluate in the current context.\n"
42
+ throw :debug_error
39
43
  end
40
44
  IRB.start_session(@state.binding)
41
45
  end
@@ -1,10 +1,17 @@
1
1
  module Debugger
2
2
  module VarFunctions # :nodoc:
3
- def var_list(ary, bind = nil)
4
- bind ||= @state.binding
3
+ def var_list(ary, bind = @state.binding)
5
4
  ary.sort!
6
5
  for v in ary
7
- print " %s => %s\n", v, eval(v, bind).inspect
6
+ print " %s => %s\n", v, debug_eval(v, bind).inspect
7
+ end
8
+ end
9
+
10
+ def var_consts(mod)
11
+ constants = mod.constants
12
+ constants.sort!
13
+ for c in constants
14
+ print " %s => %s\n", c, mod.const_get(c)
8
15
  end
9
16
  end
10
17
  end
@@ -21,7 +28,7 @@ module Debugger
21
28
  unless obj.kind_of? Module
22
29
  print "Should be Class/Module: %s\n", @match.post_match
23
30
  else
24
- var_list(obj.constants, obj.module_eval{binding()})
31
+ var_consts(obj)
25
32
  end
26
33
  end
27
34
 
@@ -95,7 +102,7 @@ module Debugger
95
102
  end
96
103
 
97
104
  def execute
98
- var_list(eval("local_variables", @state.binding))
105
+ var_list(debug_eval("local_variables"))
99
106
  end
100
107
 
101
108
  class << self
@@ -62,9 +62,9 @@ module Debugger
62
62
  end
63
63
  protect :at_tracing
64
64
 
65
- def at_line(context, file, line, binding, frames = context.frames)
65
+ def at_line(context, file, line, frames = context.frames)
66
66
  print "%s:%d: %s", file, line, Debugger.line_at(file, line)
67
- process_commands(context, file, line, binding, frames)
67
+ process_commands(context, file, line, frames)
68
68
  end
69
69
  protect :at_line
70
70
 
@@ -82,13 +82,13 @@ module Debugger
82
82
  end
83
83
  end
84
84
 
85
- def process_commands(context, file, line, binding, frames)
85
+ def process_commands(context, file, line, frames)
86
86
  event_cmds = Command.commands.select{|cmd| cmd.event }
87
87
  state = State.new do |s|
88
88
  s.context = context
89
89
  s.file = file
90
90
  s.line = line
91
- s.binding = binding
91
+ s.binding = frames.first.binding
92
92
  s.display = display
93
93
  s.interface = interface
94
94
  s.commands = event_cmds
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.1
3
3
  specification_version: 1
4
4
  name: ruby-debug
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.5.3
7
- date: 2007-01-21 03:38:07 -05:00
6
+ version: "0.6"
7
+ date: 2007-01-26 15:22:30 -05:00
8
8
  summary: Fast Ruby debugger
9
9
  require_paths:
10
10
  - lib
@@ -57,6 +57,7 @@ files:
57
57
  - lib/ruby-debug/commands/variables.rb
58
58
  - ext/extconf.rb
59
59
  - ext/ruby_debug.c
60
+ - ext/tags
60
61
  - ext/win32
61
62
  - bin/rdebug
62
63
  test_files: []