ruby-debug 0.1.2 → 0.1.3

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.
Files changed (4) hide show
  1. data/Rakefile +1 -1
  2. data/ext/ruby_debug.c +258 -201
  3. data/lib/ruby-debug.rb +379 -363
  4. metadata +2 -2
data/ext/ruby_debug.c CHANGED
@@ -4,7 +4,7 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.1.2"
7
+ #define DEBUG_VERSION "0.1.3"
8
8
 
9
9
  typedef struct {
10
10
  int thnum;
@@ -29,7 +29,7 @@ typedef struct {
29
29
  typedef struct {
30
30
  VALUE source;
31
31
  VALUE pos;
32
- VALUE disabled;
32
+ VALUE expr;
33
33
  } debug_breakpoint_t;
34
34
 
35
35
  static VALUE threads_tbl = Qnil;
@@ -110,8 +110,8 @@ thread_context_lookup(VALUE thread)
110
110
  context = rb_hash_aref(threads_tbl, thread);
111
111
  if(context == Qnil)
112
112
  {
113
- context = debug_context_create(thread);
114
- rb_hash_aset(threads_tbl, thread, context);
113
+ context = debug_context_create(thread);
114
+ rb_hash_aset(threads_tbl, thread, context);
115
115
  }
116
116
  return context;
117
117
  }
@@ -142,12 +142,11 @@ debug_frame_create(VALUE file, VALUE line, VALUE binding, ID id)
142
142
  }
143
143
 
144
144
  static VALUE
145
- call_debug_command(VALUE context, int thnum, VALUE self, ID mid, VALUE file, VALUE line)
145
+ call_debug_command(VALUE context, int thnum, VALUE binding, ID mid, VALUE file, VALUE line)
146
146
  {
147
- VALUE id, binding;
147
+ VALUE id;
148
148
 
149
149
  id = mid ? ID2SYM(mid) : Qnil;
150
- binding = self? create_binding(self) : Qnil;
151
150
 
152
151
  last_debugged_thnum = thnum;
153
152
  debug_suspend(mDebugger);
@@ -162,10 +161,10 @@ set_frame_source(debug_context_t *debug_context, VALUE file, VALUE line)
162
161
 
163
162
  if(RARRAY(debug_context->frames)->len > 0)
164
163
  {
165
- frame = *RARRAY(debug_context->frames)->ptr;
166
- Data_Get_Struct(frame, debug_frame_t, top_frame);
167
- top_frame->file = file;
168
- top_frame->line = line;
164
+ frame = *RARRAY(debug_context->frames)->ptr;
165
+ Data_Get_Struct(frame, debug_frame_t, top_frame);
166
+ top_frame->file = file;
167
+ top_frame->line = line;
169
168
  }
170
169
  }
171
170
 
@@ -180,33 +179,26 @@ save_call_frame(VALUE self, VALUE file, VALUE line, ID mid, debug_context_t *deb
180
179
  }
181
180
 
182
181
  static int
183
- check_breakpoints(VALUE context, VALUE file, VALUE klass, VALUE pos, ID id)
182
+ check_breakpoints(VALUE context, VALUE file, VALUE klass, VALUE pos)
184
183
  {
185
184
  VALUE breakpoint;
186
185
  debug_breakpoint_t *debug_breakpoint;
187
186
  int i;
188
- int result = 0;
189
187
 
190
188
  if(RARRAY(breakpoints)->len == 0)
191
- return 0;
189
+ return -1;
192
190
  for(i = 0; i < RARRAY(breakpoints)->len; i++)
193
191
  {
194
- breakpoint = rb_ary_entry(breakpoints, i);
195
- Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
196
- if(debug_breakpoint->pos != pos && !(TYPE(pos) == T_STRING &&
197
- TYPE(debug_breakpoint->pos) == T_STRING && rb_str_cmp(debug_breakpoint->pos, pos) == 0))
198
- continue;
199
- if(TYPE(debug_breakpoint->source) == T_STRING &&
200
- rb_str_cmp(debug_breakpoint->source, file) == 0 ||
201
- klass != Qnil && debug_breakpoint->source == klass)
202
- {
203
- result = 1;
204
- rb_funcall(context, idAtBreakpoint, 2, breakpoint, id ? rb_str_new2(rb_id2name(id)) : Qnil);
205
- continue;
206
- }
207
-
192
+ breakpoint = rb_ary_entry(breakpoints, i);
193
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
194
+ if(debug_breakpoint->pos != pos && !(TYPE(pos) == T_STRING &&
195
+ TYPE(debug_breakpoint->pos) == T_STRING && rb_str_cmp(debug_breakpoint->pos, pos) == 0))
196
+ continue;
197
+ if(rb_str_cmp(debug_breakpoint->source, file) == 0 ||
198
+ klass != Qnil && rb_str_cmp(debug_breakpoint->source, rb_mod_name(klass)) == 0)
199
+ return i;
208
200
  }
209
- return result;
201
+ return -1;
210
202
  }
211
203
 
212
204
  /*
@@ -221,11 +213,11 @@ create_binding(VALUE self)
221
213
 
222
214
  if(f_binding == NULL)
223
215
  {
224
- ID idBinding = rb_intern("binding");
225
- NODE *body, *method;
226
- st_lookup(RCLASS(rb_mKernel)->m_tbl, idBinding, (st_data_t *)&body);
227
- method = (NODE *)body->u2.value;
228
- f_binding = (bind_func_t)method->u1.value;
216
+ ID idBinding = rb_intern("binding");
217
+ NODE *body, *method;
218
+ st_lookup(RCLASS(rb_mKernel)->m_tbl, idBinding, (st_data_t *)&body);
219
+ method = (NODE *)body->u2.value;
220
+ f_binding = (bind_func_t)method->u1.value;
229
221
  }
230
222
  return f_binding(self);
231
223
  }
@@ -234,26 +226,54 @@ static void
234
226
  check_suspend(debug_context_t *debug_context)
235
227
  {
236
228
  if(rb_thread_critical == Qtrue)
237
- return;
229
+ return;
238
230
  while(1)
239
231
  {
240
- rb_thread_critical = Qtrue;
241
- if(!debug_context->suspend)
242
- break;
243
- rb_ary_push(waiting, rb_thread_current());
244
- debug_context->suspend = 0;
245
- rb_thread_stop();
232
+ rb_thread_critical = Qtrue;
233
+ if(!debug_context->suspend)
234
+ break;
235
+ rb_ary_push(waiting, rb_thread_current());
236
+ debug_context->suspend = 0;
237
+ rb_thread_stop();
246
238
  }
247
239
  rb_thread_critical = Qfalse;
248
240
  }
249
241
 
242
+ static VALUE
243
+ get_breakpoint_at(int index)
244
+ {
245
+ return rb_ary_entry(breakpoints, index);
246
+ }
247
+
248
+ static VALUE
249
+ eval_expression(VALUE args)
250
+ {
251
+ return rb_funcall(rb_mKernel, rb_intern("eval"), 2, RARRAY(args)->ptr[0], RARRAY(args)->ptr[1]);
252
+ }
253
+
254
+ static int
255
+ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
256
+ {
257
+ debug_breakpoint_t *debug_breakpoint;
258
+ VALUE args, expr_result;
259
+
260
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
261
+ if(NIL_P(debug_breakpoint->expr))
262
+ return 1;
263
+
264
+ args = rb_ary_new3(2, debug_breakpoint->expr, binding);
265
+ expr_result = rb_protect(eval_expression, args, 0);
266
+ return RTEST(expr_result);
267
+ }
268
+
250
269
  static void
251
270
  debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
252
271
  {
253
- VALUE thread;
254
- VALUE context;
272
+ VALUE thread, context, binding, breakpoint;
255
273
  debug_context_t *debug_context;
274
+ debug_breakpoint_t *debug_breakpoint;
256
275
  VALUE file = Qnil, line = Qnil;
276
+ int breakpoint_index = -1;
257
277
 
258
278
  static int debugging = 0;
259
279
 
@@ -268,123 +288,142 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
268
288
 
269
289
  if(node)
270
290
  {
271
- file = rb_str_new2(node->nd_file);
272
- line = INT2FIX(nd_line(node));
291
+ file = rb_str_new2(node->nd_file);
292
+ line = INT2FIX(nd_line(node));
273
293
  }
274
294
 
275
295
  switch(event)
276
296
  {
277
- case RUBY_EVENT_LINE:
278
- {
279
- set_frame_source(debug_context, file, line);
280
-
281
- if(RTEST(tracing) || debug_context->tracing )
282
- {
283
- rb_funcall(context, idAtTracing, 2, file, line);
284
- }
285
-
286
- if(debug_context->dest_frame == -1 ||
287
- RARRAY(debug_context->frames)->len == debug_context->dest_frame)
288
- {
289
- debug_context->stop_next--;
290
- if(debug_context->stop_next < 0)
291
- debug_context->stop_next = -1;
292
- /* we check that we actualy moved to another line */
293
- if(line != Qnil && debug_context->src_line != FIX2INT(line))
294
- {
295
- debug_context->stop_line--;
296
- }
297
- }
298
- else if(RARRAY(debug_context->frames)->len < debug_context->dest_frame)
299
- {
300
- debug_context->stop_next = 0;
301
- }
302
-
303
- if(RARRAY(debug_context->frames)->len == 0)
304
- {
305
- save_call_frame(self, file, line, mid, debug_context);
306
- }
307
-
308
- if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
309
- check_breakpoints(context, file, klass, line, mid))
310
- {
311
- /* reset all pointers */
312
- debug_context->dest_frame = -1;
313
- debug_context->src_line = -1;
314
- debug_context->stop_line = -1;
315
- debug_context->stop_next = -1;
316
-
317
- call_debug_command(context, debug_context->thnum, self, mid, file, line);
318
- }
319
- break;
320
- }
321
- case RUBY_EVENT_C_CALL:
322
- {
323
- if(node)
324
- {
325
- set_frame_source(debug_context, file, line);
326
- }
327
- break;
328
- }
329
- case RUBY_EVENT_CALL:
330
- {
331
- save_call_frame(self, file, line, mid, debug_context);
332
- if(check_breakpoints(context, file, klass, rb_str_new2(rb_id2name(mid)), mid))
333
- {
334
- call_debug_command(context, debug_context->thnum, self, mid, file, line);
335
- }
336
- break;
337
- }
338
- case RUBY_EVENT_RETURN:
339
- case RUBY_EVENT_END:
340
- {
341
- if(RARRAY(debug_context->frames)->len == debug_context->stop_frame)
342
- {
343
- debug_context->stop_next = 1;
344
- debug_context->stop_frame = 0;
345
- }
346
- rb_ary_shift(debug_context->frames);
347
- break;
348
- }
349
- case RUBY_EVENT_CLASS:
350
- {
351
- save_call_frame(self, file, line, mid, debug_context);
352
- break;
353
- }
354
- case RUBY_EVENT_RAISE:
355
- {
356
- VALUE ancestors;
357
- VALUE expn_class, aclass;
358
- int i, found = 0;
359
-
360
- expn_class = rb_obj_class(ruby_errinfo);
361
- if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
362
- {
363
- debug_stop(mDebugger);
364
- rb_exit(0);
365
- }
366
-
367
- if(catchpoint == Qnil)
368
- break;
369
-
370
- ancestors = rb_mod_ancestors(expn_class);
371
- for(i = 0; i < RARRAY(ancestors)->len; i++)
372
- {
373
- aclass = rb_ary_entry(ancestors, i);
374
- if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
375
- {
376
- rb_funcall(context, idAtCatchpoint, 0);
377
- call_debug_command(context, debug_context->thnum, self, mid, file, line);
378
- break;
379
- }
380
- }
381
-
382
- break;
383
- }
384
- case RUBY_EVENT_C_RETURN:
385
- {
386
- break;
387
- }
297
+ case RUBY_EVENT_LINE:
298
+ {
299
+ set_frame_source(debug_context, file, line);
300
+
301
+ if(RTEST(tracing) || debug_context->tracing )
302
+ {
303
+ rb_funcall(context, idAtTracing, 2, file, line);
304
+ }
305
+
306
+ if(debug_context->dest_frame == -1 ||
307
+ RARRAY(debug_context->frames)->len == debug_context->dest_frame)
308
+ {
309
+ debug_context->stop_next--;
310
+ if(debug_context->stop_next < 0)
311
+ debug_context->stop_next = -1;
312
+ /* we check that we actualy moved to another line */
313
+ if(line != Qnil && debug_context->src_line != FIX2INT(line))
314
+ {
315
+ debug_context->stop_line--;
316
+ }
317
+ }
318
+ else if(RARRAY(debug_context->frames)->len < debug_context->dest_frame)
319
+ {
320
+ debug_context->stop_next = 0;
321
+ }
322
+
323
+ if(RARRAY(debug_context->frames)->len == 0)
324
+ {
325
+ save_call_frame(self, file, line, mid, debug_context);
326
+ }
327
+
328
+ if(debug_context->stop_next == 0 || debug_context->stop_line == 0 ||
329
+ (breakpoint_index = check_breakpoints(context, file, klass, line)) != -1)
330
+ {
331
+ binding = self? create_binding(self) : Qnil;
332
+ /* check breakpoint expression */
333
+ if(breakpoint_index != -1)
334
+ {
335
+ breakpoint = get_breakpoint_at(breakpoint_index);
336
+ if(check_breakpoint_expression(breakpoint, binding))
337
+ rb_funcall(context, idAtBreakpoint, 2, breakpoint, mid ? rb_str_new2(rb_id2name(mid)) : Qnil);
338
+ else
339
+ break;
340
+ }
341
+
342
+ /* reset all pointers */
343
+ debug_context->dest_frame = -1;
344
+ debug_context->src_line = -1;
345
+ debug_context->stop_line = -1;
346
+ debug_context->stop_next = -1;
347
+
348
+ call_debug_command(context, debug_context->thnum, binding, mid, file, line);
349
+ }
350
+ break;
351
+ }
352
+ case RUBY_EVENT_C_CALL:
353
+ {
354
+ if(node)
355
+ {
356
+ set_frame_source(debug_context, file, line);
357
+ }
358
+ break;
359
+ }
360
+ case RUBY_EVENT_CALL:
361
+ {
362
+ save_call_frame(self, file, line, mid, debug_context);
363
+ breakpoint_index = check_breakpoints(context, file, klass, rb_str_new2(rb_id2name(mid)));
364
+ if(breakpoint_index != -1)
365
+ {
366
+ binding = self? create_binding(self) : Qnil;
367
+ breakpoint = get_breakpoint_at(breakpoint_index);
368
+ if(check_breakpoint_expression(breakpoint, binding))
369
+ {
370
+ rb_funcall(context, idAtBreakpoint, 2, breakpoint, mid ? rb_str_new2(rb_id2name(mid)) : Qnil);
371
+ call_debug_command(context, debug_context->thnum, binding, mid, file, line);
372
+ }
373
+ }
374
+ break;
375
+ }
376
+ case RUBY_EVENT_RETURN:
377
+ case RUBY_EVENT_END:
378
+ {
379
+ if(RARRAY(debug_context->frames)->len == debug_context->stop_frame)
380
+ {
381
+ debug_context->stop_next = 1;
382
+ debug_context->stop_frame = 0;
383
+ }
384
+ rb_ary_shift(debug_context->frames);
385
+ break;
386
+ }
387
+ case RUBY_EVENT_CLASS:
388
+ {
389
+ save_call_frame(self, file, line, mid, debug_context);
390
+ break;
391
+ }
392
+ case RUBY_EVENT_RAISE:
393
+ {
394
+ VALUE ancestors;
395
+ VALUE expn_class, aclass;
396
+ int i, found = 0;
397
+
398
+ expn_class = rb_obj_class(ruby_errinfo);
399
+ if( !NIL_P(rb_class_inherited_p(expn_class, rb_eSystemExit)) )
400
+ {
401
+ debug_stop(mDebugger);
402
+ rb_exit(0);
403
+ }
404
+
405
+ if(catchpoint == Qnil)
406
+ break;
407
+
408
+ ancestors = rb_mod_ancestors(expn_class);
409
+ for(i = 0; i < RARRAY(ancestors)->len; i++)
410
+ {
411
+ aclass = rb_ary_entry(ancestors, i);
412
+ if(rb_str_cmp(rb_mod_name(aclass), catchpoint) == 0)
413
+ {
414
+ rb_funcall(context, idAtCatchpoint, 0);
415
+ binding = self? create_binding(self) : Qnil;
416
+ call_debug_command(context, debug_context->thnum, binding, mid, file, line);
417
+ break;
418
+ }
419
+ }
420
+
421
+ break;
422
+ }
423
+ case RUBY_EVENT_C_RETURN:
424
+ {
425
+ break;
426
+ }
388
427
  }
389
428
 
390
429
  debugging--;
@@ -410,10 +449,10 @@ debug_start(VALUE self)
410
449
  waiting = rb_ary_new();
411
450
 
412
451
  rb_add_event_hook(debug_event_hook,
413
- RUBY_EVENT_LINE | RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
414
- RUBY_EVENT_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_CLASS |
415
- RUBY_EVENT_END | RUBY_EVENT_RAISE
416
- );
452
+ RUBY_EVENT_LINE | RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
453
+ RUBY_EVENT_CALL | RUBY_EVENT_RETURN | RUBY_EVENT_CLASS |
454
+ RUBY_EVENT_END | RUBY_EVENT_RAISE
455
+ );
417
456
  return Qnil;
418
457
  }
419
458
 
@@ -437,20 +476,27 @@ breakpoint_mark(void *data)
437
476
  breakpoint = (debug_breakpoint_t *)data;
438
477
  rb_gc_mark(breakpoint->source);
439
478
  rb_gc_mark(breakpoint->pos);
479
+ rb_gc_mark(breakpoint->expr);
440
480
  }
441
481
 
442
482
  static VALUE
443
- debug_add_breakpoint(VALUE self, VALUE source, VALUE pos)
483
+ debug_add_breakpoint(int argc, VALUE *argv, VALUE self)
444
484
  {
485
+ VALUE source, pos, expr;
445
486
  VALUE result;
446
487
  debug_breakpoint_t *breakpoint;
447
488
 
448
489
  debug_check_started();
490
+
491
+ if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
492
+ {
493
+ expr = Qnil;
494
+ }
449
495
 
450
496
  breakpoint = ALLOC(debug_breakpoint_t);
451
- breakpoint->source = source;
497
+ breakpoint->source = StringValue(source);
452
498
  breakpoint->pos = pos;
453
- breakpoint->disabled = Qfalse;
499
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
454
500
  result = Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
455
501
  rb_ary_push(breakpoints, result);
456
502
  return result;
@@ -478,12 +524,12 @@ debug_set_catchpoint(VALUE self, VALUE value)
478
524
  debug_check_started();
479
525
 
480
526
  if (!NIL_P(value) && TYPE(value) != T_STRING) {
481
- rb_raise(rb_eTypeError, "value of checkpoint must be String");
527
+ rb_raise(rb_eTypeError, "value of checkpoint must be String");
482
528
  }
483
529
  if(NIL_P(value))
484
- catchpoint = Qnil;
530
+ catchpoint = Qnil;
485
531
  else
486
- catchpoint = rb_str_dup(value);
532
+ catchpoint = rb_str_dup(value);
487
533
  return value;
488
534
  }
489
535
 
@@ -510,8 +556,8 @@ find_last_context_func(VALUE key, VALUE value, VALUE *result)
510
556
  Data_Get_Struct(value, debug_context_t, debug_context);
511
557
  if(debug_context->thnum == last_debugged_thnum)
512
558
  {
513
- *result = value;
514
- return ST_STOP;
559
+ *result = value;
560
+ return ST_STOP;
515
561
  }
516
562
  return ST_CONTINUE;
517
563
  }
@@ -535,8 +581,8 @@ debug_interrupt_last(VALUE self)
535
581
  context = find_last_context();
536
582
  if(context != Qnil)
537
583
  {
538
- Data_Get_Struct(context, debug_context_t, debug_context);
539
- debug_context->stop_next = 1;
584
+ Data_Get_Struct(context, debug_context_t, debug_context);
585
+ debug_context->stop_next = 1;
540
586
  }
541
587
 
542
588
  return Qnil;
@@ -570,9 +616,9 @@ debug_contexts(VALUE self)
570
616
  list = rb_funcall(rb_cThread, rb_intern("list"), 0);
571
617
  for(i = 0; i < RARRAY(list)->len; i++)
572
618
  {
573
- thread = rb_ary_entry(list, i);
574
- context = thread_context_lookup(thread);
575
- rb_ary_push(new_list, context);
619
+ thread = rb_ary_entry(list, i);
620
+ context = thread_context_lookup(thread);
621
+ rb_ary_push(new_list, context);
576
622
  }
577
623
  /*
578
624
  * I wonder why rb_hash_clear is declared static?
@@ -580,9 +626,9 @@ debug_contexts(VALUE self)
580
626
  rb_funcall(threads_tbl, rb_intern("clear"), 0);
581
627
  for(i = 0; i < RARRAY(new_list)->len; i++)
582
628
  {
583
- context = rb_ary_entry(new_list, i);
584
- Data_Get_Struct(context, debug_context_t, debug_context);
585
- rb_hash_aset(threads_tbl, debug_context->thread, context);
629
+ context = rb_ary_entry(new_list, i);
630
+ Data_Get_Struct(context, debug_context_t, debug_context);
631
+ rb_hash_aset(threads_tbl, debug_context->thread, context);
586
632
  }
587
633
 
588
634
  return new_list;
@@ -606,16 +652,16 @@ debug_suspend(VALUE self)
606
652
 
607
653
  for(i = 0; i < RARRAY(context_list)->len; i++)
608
654
  {
609
- context = rb_ary_entry(context_list, i);
610
- if(current == context)
611
- continue;
612
- Data_Get_Struct(context, debug_context_t, debug_context);
613
- debug_context->suspend = 1;
655
+ context = rb_ary_entry(context_list, i);
656
+ if(current == context)
657
+ continue;
658
+ Data_Get_Struct(context, debug_context_t, debug_context);
659
+ debug_context->suspend = 1;
614
660
  }
615
661
  rb_thread_critical = saved_crit;
616
662
 
617
663
  if(rb_thread_critical == Qfalse)
618
- rb_thread_schedule();
664
+ rb_thread_schedule();
619
665
 
620
666
  return context;
621
667
  }
@@ -639,16 +685,16 @@ debug_resume(VALUE self)
639
685
  current = thread_context_lookup(rb_thread_current());
640
686
  for(i = 0; i < RARRAY(context_list)->len; i++)
641
687
  {
642
- context = rb_ary_entry(context_list, i);
643
- if(current == context)
644
- continue;
645
- Data_Get_Struct(context, debug_context_t, debug_context);
646
- debug_context->suspend = 0;
688
+ context = rb_ary_entry(context_list, i);
689
+ if(current == context)
690
+ continue;
691
+ Data_Get_Struct(context, debug_context_t, debug_context);
692
+ debug_context->suspend = 0;
647
693
  }
648
694
  for(i = 0; i < RARRAY(waiting)->len; i++)
649
695
  {
650
- thread = rb_ary_entry(waiting, i);
651
- rb_thread_run(thread);
696
+ thread = rb_ary_entry(waiting, i);
697
+ rb_thread_run(thread);
652
698
  }
653
699
  rb_ary_clear(waiting);
654
700
  rb_thread_critical = saved_crit;
@@ -680,7 +726,7 @@ context_stop_next(VALUE self, VALUE steps)
680
726
 
681
727
  Data_Get_Struct(self, debug_context_t, debug_context);
682
728
  if(FIX2INT(steps) < 0)
683
- rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
729
+ rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
684
730
  debug_context->stop_next = FIX2INT(steps);
685
731
 
686
732
  return steps;
@@ -697,25 +743,25 @@ context_step_over(int argc, VALUE *argv, VALUE self)
697
743
 
698
744
  Data_Get_Struct(self, debug_context_t, debug_context);
699
745
  if(RARRAY(debug_context->frames)->len == 0)
700
- rb_raise(rb_eRuntimeError, "No frames collected.");
746
+ rb_raise(rb_eRuntimeError, "No frames collected.");
701
747
 
702
748
  rb_scan_args(argc, argv, "11", &lines, &frame);
703
749
  debug_context->stop_line = FIX2INT(lines);
704
750
  if(argc == 1)
705
751
  {
706
- debug_context->dest_frame = RARRAY(debug_context->frames)->len;
752
+ debug_context->dest_frame = RARRAY(debug_context->frames)->len;
707
753
  }
708
754
  else
709
755
  {
710
- if(FIX2INT(frame) < 0 && FIX2INT(frame) >= RARRAY(debug_context->frames)->len)
711
- rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
712
- debug_context->dest_frame = FIX2INT(frame);
756
+ if(FIX2INT(frame) < 0 && FIX2INT(frame) >= RARRAY(debug_context->frames)->len)
757
+ rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
758
+ debug_context->dest_frame = FIX2INT(frame);
713
759
  }
714
-
760
+
715
761
  cur_frame = *RARRAY(debug_context->frames)->ptr;
716
762
  Data_Get_Struct(cur_frame, debug_frame_t, debug_frame);
717
763
  debug_context->src_line = FIX2INT(debug_frame->line);
718
-
764
+
719
765
  return Qnil;
720
766
  }
721
767
 
@@ -725,12 +771,12 @@ context_stop_frame(VALUE self, VALUE frame)
725
771
  debug_context_t *debug_context;
726
772
 
727
773
  debug_check_started();
728
-
774
+
729
775
  Data_Get_Struct(self, debug_context_t, debug_context);
730
776
  if(FIX2INT(frame) < 0 && FIX2INT(frame) >= RARRAY(debug_context->frames)->len)
731
- rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
777
+ rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
732
778
  debug_context->stop_frame = FIX2INT(frame);
733
-
779
+
734
780
  return frame;
735
781
  }
736
782
 
@@ -862,6 +908,16 @@ breakpoint_pos(VALUE self)
862
908
  return breakpoint->pos;
863
909
  }
864
910
 
911
+ static VALUE
912
+ breakpoint_expr(VALUE self)
913
+ {
914
+ debug_breakpoint_t *breakpoint;
915
+
916
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
917
+ return breakpoint->expr;
918
+ }
919
+
920
+
865
921
  #if defined(_WIN32)
866
922
  __declspec(dllexport)
867
923
  #endif
@@ -875,7 +931,7 @@ Init_ruby_debug()
875
931
  rb_define_module_function(mDebugger, "started?", debug_is_started, 0);
876
932
  rb_define_module_function(mDebugger, "thnum", debug_thnum, 0);
877
933
  rb_define_module_function(mDebugger, "breakpoints", debug_breakpoints, 0);
878
- rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, 2);
934
+ rb_define_module_function(mDebugger, "add_breakpoint", debug_add_breakpoint, -1);
879
935
  rb_define_module_function(mDebugger, "catchpoint", debug_catchpoint, 0);
880
936
  rb_define_module_function(mDebugger, "catchpoint=", debug_set_catchpoint, 1);
881
937
  rb_define_module_function(mDebugger, "interrupt", debug_interrupt, 0);
@@ -908,6 +964,7 @@ Init_ruby_debug()
908
964
  cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
909
965
  rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
910
966
  rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
967
+ rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
911
968
 
912
969
  idDebugCommand = rb_intern("debug_command");
913
970
  idAtBreakpoint = rb_intern("at_breakpoint");