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.
- data/Rakefile +1 -1
- data/ext/ruby_debug.c +258 -201
- data/lib/ruby-debug.rb +379 -363
- 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.
|
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
|
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
|
-
|
114
|
-
|
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
|
145
|
+
call_debug_command(VALUE context, int thnum, VALUE binding, ID mid, VALUE file, VALUE line)
|
146
146
|
{
|
147
|
-
VALUE id
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
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
|
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
|
-
|
189
|
+
return -1;
|
192
190
|
for(i = 0; i < RARRAY(breakpoints)->len; i++)
|
193
191
|
{
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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
|
-
|
229
|
+
return;
|
238
230
|
while(1)
|
239
231
|
{
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
-
|
272
|
-
|
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
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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
|
-
|
414
|
-
|
415
|
-
|
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(
|
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->
|
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
|
-
|
527
|
+
rb_raise(rb_eTypeError, "value of checkpoint must be String");
|
482
528
|
}
|
483
529
|
if(NIL_P(value))
|
484
|
-
|
530
|
+
catchpoint = Qnil;
|
485
531
|
else
|
486
|
-
|
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
|
-
|
514
|
-
|
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
|
-
|
539
|
-
|
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
|
-
|
574
|
-
|
575
|
-
|
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
|
-
|
584
|
-
|
585
|
-
|
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
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
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
|
-
|
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
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
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
|
-
|
651
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
752
|
+
debug_context->dest_frame = RARRAY(debug_context->frames)->len;
|
707
753
|
}
|
708
754
|
else
|
709
755
|
{
|
710
|
-
|
711
|
-
|
712
|
-
|
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
|
-
|
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,
|
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");
|