ruby-debug 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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");