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