debugger 1.3.3 → 1.4.0

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/.travis.yml CHANGED
@@ -2,3 +2,7 @@ before_script: rake compile
2
2
  rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ - 2.0.0
6
+ matrix:
7
+ allow_failures:
8
+ - rvm: 2.0.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 1.4.0
2
+ * Partial support for 2.0.0
3
+
1
4
  ## 1.3.3
2
5
  * Bump ruby_core_source dependency
3
6
 
data/README.md CHANGED
@@ -104,6 +104,7 @@ tutorial](http://bashdb.sourceforge.net/ruby-debug/rdebug-emacs.html)
104
104
  Please report them [on github](http://github.com/cldwalker/debugger/issues).
105
105
 
106
106
  ## Known Issues
107
+ * 2.0.0 support is only partially working and the test suite dies before it can finish.
107
108
  * If you place a debugger call at the end of a block, debugging will start at the next step and
108
109
  outside of your block. A simple work-around is to place a meaningless step (i.e. puts "STAY")
109
110
  at the end of your block and before debugger.
@@ -128,6 +129,7 @@ Let's keep this working for the ruby community!
128
129
 
129
130
  * Thanks to the original authors: Kent Sibilev and Mark Moseley
130
131
  * Thanks to astashov for bringing in a new and improved test suite and various bug fixes.
132
+ * Thanks to windwiny for porting to 2.0.0
131
133
  * Contributors: ericpromislow, jnimety, adammck, hipe, FooBarWidget, aghull
132
134
  * Fork started on awesome @relevance fridays!
133
135
 
@@ -0,0 +1,586 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <vm_core.h>
4
+ #include <iseq.h>
5
+ #include "ruby_debug.h"
6
+
7
+ VALUE rdebug_breakpoints = Qnil;
8
+ VALUE rdebug_catchpoints;
9
+
10
+ static VALUE cBreakpoint;
11
+ static ID idEval;
12
+
13
+ static VALUE
14
+ eval_expression(VALUE args)
15
+ {
16
+ return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
17
+ }
18
+
19
+ int
20
+ check_breakpoint_hit_condition(VALUE breakpoint)
21
+ {
22
+ debug_breakpoint_t *debug_breakpoint;
23
+
24
+ if(breakpoint == Qnil)
25
+ return 0;
26
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
27
+
28
+ debug_breakpoint->hit_count++;
29
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
30
+ switch(debug_breakpoint->hit_condition)
31
+ {
32
+ case HIT_COND_NONE:
33
+ return 1;
34
+ case HIT_COND_GE:
35
+ {
36
+ if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value)
37
+ return 1;
38
+ break;
39
+ }
40
+ case HIT_COND_EQ:
41
+ {
42
+ if(debug_breakpoint->hit_count == debug_breakpoint->hit_value)
43
+ return 1;
44
+ break;
45
+ }
46
+ case HIT_COND_MOD:
47
+ {
48
+ if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0)
49
+ return 1;
50
+ break;
51
+ }
52
+ }
53
+ return 0;
54
+ }
55
+
56
+ static int
57
+ check_breakpoint_by_pos(VALUE breakpoint, char *file, int line)
58
+ {
59
+ debug_breakpoint_t *debug_breakpoint;
60
+
61
+ if(breakpoint == Qnil)
62
+ return 0;
63
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
64
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
65
+ if(debug_breakpoint->type != BP_POS_TYPE)
66
+ return 0;
67
+ if(debug_breakpoint->pos.line != line)
68
+ return 0;
69
+ if(filename_cmp(debug_breakpoint->source, file))
70
+ return 1;
71
+ return 0;
72
+ }
73
+
74
+ int
75
+ check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid, VALUE self)
76
+ {
77
+ debug_breakpoint_t *debug_breakpoint;
78
+
79
+ if(breakpoint == Qnil)
80
+ return 0;
81
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
82
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
83
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
84
+ return 0;
85
+ if(debug_breakpoint->pos.mid != mid)
86
+ return 0;
87
+ if(classname_cmp(debug_breakpoint->source, klass))
88
+ return 1;
89
+ if ((rb_type(self) == T_CLASS) &&
90
+ classname_cmp(debug_breakpoint->source, self))
91
+ return 1;
92
+ return 0;
93
+ }
94
+
95
+ VALUE
96
+ check_breakpoints_by_pos(debug_context_t *debug_context, char *file, int line)
97
+ {
98
+ VALUE breakpoint;
99
+ int i;
100
+
101
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
102
+ return Qnil;
103
+
104
+ if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
105
+ return debug_context->breakpoint;
106
+
107
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
108
+ return Qnil;
109
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
110
+ {
111
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
112
+ if(check_breakpoint_by_pos(breakpoint, file, line))
113
+ return breakpoint;
114
+ }
115
+ return Qnil;
116
+ }
117
+
118
+ VALUE
119
+ check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid, VALUE self)
120
+ {
121
+ VALUE breakpoint;
122
+ int i;
123
+
124
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
125
+ return Qnil;
126
+
127
+ if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid, self))
128
+ return debug_context->breakpoint;
129
+
130
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
131
+ return Qnil;
132
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
133
+ {
134
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
135
+ if(check_breakpoint_by_method(breakpoint, klass, mid, self))
136
+ return breakpoint;
137
+ }
138
+ return Qnil;
139
+ }
140
+
141
+ int
142
+ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
143
+ {
144
+ debug_breakpoint_t *debug_breakpoint;
145
+ VALUE args, expr_result;
146
+
147
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
148
+ if(NIL_P(debug_breakpoint->expr))
149
+ return 1;
150
+
151
+ args = rb_ary_new3(2, debug_breakpoint->expr, binding);
152
+ expr_result = rb_protect(eval_expression, args, 0);
153
+ return RTEST(expr_result);
154
+ }
155
+
156
+ static void
157
+ breakpoint_mark(void *data)
158
+ {
159
+ debug_breakpoint_t *breakpoint;
160
+ breakpoint = (debug_breakpoint_t *)data;
161
+ rb_gc_mark(breakpoint->source);
162
+ rb_gc_mark(breakpoint->expr);
163
+ }
164
+
165
+ VALUE
166
+ create_breakpoint_from_args(int argc, VALUE *argv, int id)
167
+ {
168
+ VALUE source, pos, expr;
169
+ debug_breakpoint_t *breakpoint;
170
+ int type;
171
+
172
+ if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
173
+ {
174
+ expr = Qnil;
175
+ }
176
+ type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
177
+ if(type == BP_POS_TYPE)
178
+ source = StringValue(source);
179
+ else
180
+ pos = StringValue(pos);
181
+ breakpoint = ALLOC(debug_breakpoint_t);
182
+ breakpoint->id = id;
183
+ breakpoint->source = source;
184
+ breakpoint->type = type;
185
+ if(type == BP_POS_TYPE)
186
+ breakpoint->pos.line = FIX2INT(pos);
187
+ else
188
+ breakpoint->pos.mid = rb_intern(RSTRING_PTR(pos));
189
+ breakpoint->enabled = Qtrue;
190
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
191
+ breakpoint->hit_count = 0;
192
+ breakpoint->hit_value = 0;
193
+ breakpoint->hit_condition = HIT_COND_NONE;
194
+ return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
195
+ }
196
+
197
+ /*
198
+ * call-seq:
199
+ * Debugger.remove_breakpoint(id) -> breakpoint
200
+ *
201
+ * Removes breakpoint by its id.
202
+ * <i>id</i> is an identificator of a breakpoint.
203
+ */
204
+ VALUE
205
+ rdebug_remove_breakpoint(VALUE self, VALUE id_value)
206
+ {
207
+ int i;
208
+ int id;
209
+ VALUE breakpoint;
210
+ debug_breakpoint_t *debug_breakpoint;
211
+
212
+ id = FIX2INT(id_value);
213
+
214
+ for( i = 0; i < RARRAY_LEN(rdebug_breakpoints); i += 1 )
215
+ {
216
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
217
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
218
+ if(debug_breakpoint->id == id)
219
+ {
220
+ rb_ary_delete_at(rdebug_breakpoints, i);
221
+ return breakpoint;
222
+ }
223
+ }
224
+ return Qnil;
225
+ }
226
+
227
+ /*
228
+ * call-seq:
229
+ * Debugger.catchpoints -> hash
230
+ *
231
+ * Returns a current catchpoints, which is a hash exception names that will
232
+ * trigger a debugger when raised. The values are the number of times taht
233
+ * catchpoint was hit, initially 0.
234
+ */
235
+ VALUE
236
+ debug_catchpoints(VALUE self)
237
+ {
238
+ debug_check_started();
239
+
240
+ return rdebug_catchpoints;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * Debugger.catchpoint(string) -> string
246
+ *
247
+ * Sets catchpoint. Returns the string passed.
248
+ */
249
+ VALUE
250
+ rdebug_add_catchpoint(VALUE self, VALUE value)
251
+ {
252
+ debug_check_started();
253
+
254
+ if (TYPE(value) != T_STRING) {
255
+ rb_raise(rb_eTypeError, "value of a catchpoint must be String");
256
+ }
257
+ rb_hash_aset(rdebug_catchpoints, rb_str_dup(value), INT2FIX(0));
258
+ return value;
259
+ }
260
+
261
+ /*
262
+ * call-seq:
263
+ * context.breakpoint -> breakpoint
264
+ *
265
+ * Returns a context-specific temporary Breakpoint object.
266
+ */
267
+ VALUE
268
+ context_breakpoint(VALUE self)
269
+ {
270
+ debug_context_t *debug_context;
271
+
272
+ debug_check_started();
273
+
274
+ Data_Get_Struct(self, debug_context_t, debug_context);
275
+ return debug_context->breakpoint;
276
+ }
277
+
278
+ /*
279
+ * call-seq:
280
+ * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
281
+ *
282
+ * Sets a context-specific temporary breakpoint, which can be used to implement
283
+ * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
284
+ * cleared out.
285
+ *
286
+ * <i>source</i> is a name of a file or a class.
287
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
288
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
289
+ * is activated.
290
+ */
291
+ VALUE
292
+ context_set_breakpoint(int argc, VALUE *argv, VALUE self)
293
+ {
294
+ VALUE result;
295
+ debug_context_t *debug_context;
296
+
297
+ debug_check_started();
298
+
299
+ Data_Get_Struct(self, debug_context_t, debug_context);
300
+ result = create_breakpoint_from_args(argc, argv, 0);
301
+ debug_context->breakpoint = result;
302
+ return result;
303
+ }
304
+
305
+ /*
306
+ * call-seq:
307
+ * breakpoint.enabled?
308
+ *
309
+ * Returns whether breakpoint is enabled or not.
310
+ */
311
+ static VALUE
312
+ breakpoint_enabled(VALUE self)
313
+ {
314
+ debug_breakpoint_t *breakpoint;
315
+
316
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
317
+ return breakpoint->enabled;
318
+ }
319
+
320
+ /*
321
+ * call-seq:
322
+ * breakpoint.enabled = bool
323
+ *
324
+ * Enables or disables breakpoint.
325
+ */
326
+ static VALUE
327
+ breakpoint_set_enabled(VALUE self, VALUE bool)
328
+ {
329
+ debug_breakpoint_t *breakpoint;
330
+
331
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
332
+ return breakpoint->enabled = bool;
333
+ }
334
+
335
+ /*
336
+ * call-seq:
337
+ * breakpoint.source -> string
338
+ *
339
+ * Returns a source of the breakpoint.
340
+ */
341
+ static VALUE
342
+ breakpoint_source(VALUE self)
343
+ {
344
+ debug_breakpoint_t *breakpoint;
345
+
346
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
347
+ return breakpoint->source;
348
+ }
349
+
350
+ /*
351
+ * call-seq:
352
+ * breakpoint.source = string
353
+ *
354
+ * Sets the source of the breakpoint.
355
+ */
356
+ static VALUE
357
+ breakpoint_set_source(VALUE self, VALUE value)
358
+ {
359
+ debug_breakpoint_t *breakpoint;
360
+
361
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
362
+ breakpoint->source = StringValue(value);
363
+ return value;
364
+ }
365
+
366
+ /*
367
+ * call-seq:
368
+ * breakpoint.pos -> string or int
369
+ *
370
+ * Returns the position of this breakpoint.
371
+ */
372
+ static VALUE
373
+ breakpoint_pos(VALUE self)
374
+ {
375
+ debug_breakpoint_t *breakpoint;
376
+
377
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
378
+ if(breakpoint->type == BP_METHOD_TYPE)
379
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
380
+ else
381
+ return INT2FIX(breakpoint->pos.line);
382
+ }
383
+
384
+ /*
385
+ * call-seq:
386
+ * breakpoint.pos = string or int
387
+ *
388
+ * Sets the position of this breakpoint.
389
+ */
390
+ static VALUE
391
+ breakpoint_set_pos(VALUE self, VALUE value)
392
+ {
393
+ debug_breakpoint_t *breakpoint;
394
+
395
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
396
+ if(breakpoint->type == BP_METHOD_TYPE)
397
+ {
398
+ breakpoint->pos.mid = rb_to_id(StringValue(value));
399
+ }
400
+ else
401
+ breakpoint->pos.line = FIX2INT(value);
402
+ return value;
403
+ }
404
+
405
+ /*
406
+ * call-seq:
407
+ * breakpoint.expr -> string
408
+ *
409
+ * Returns a codition expression when this breakpoint should be activated.
410
+ */
411
+ static VALUE
412
+ breakpoint_expr(VALUE self)
413
+ {
414
+ debug_breakpoint_t *breakpoint;
415
+
416
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
417
+ return breakpoint->expr;
418
+ }
419
+
420
+ /*
421
+ * call-seq:
422
+ * breakpoint.expr = string | nil
423
+ *
424
+ * Sets the codition expression when this breakpoint should be activated.
425
+ */
426
+ static VALUE
427
+ breakpoint_set_expr(VALUE self, VALUE expr)
428
+ {
429
+ debug_breakpoint_t *breakpoint;
430
+
431
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
432
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
433
+ return expr;
434
+ }
435
+
436
+ /*
437
+ * call-seq:
438
+ * breakpoint.id -> int
439
+ *
440
+ * Returns id of the breakpoint.
441
+ */
442
+ static VALUE
443
+ breakpoint_id(VALUE self)
444
+ {
445
+ debug_breakpoint_t *breakpoint;
446
+
447
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
448
+ return INT2FIX(breakpoint->id);
449
+ }
450
+
451
+ /*
452
+ * call-seq:
453
+ * breakpoint.hit_count -> int
454
+ *
455
+ * Returns the hit count of the breakpoint.
456
+ */
457
+ static VALUE
458
+ breakpoint_hit_count(VALUE self)
459
+ {
460
+ debug_breakpoint_t *breakpoint;
461
+
462
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
463
+ return INT2FIX(breakpoint->hit_count);
464
+ }
465
+
466
+ /*
467
+ * call-seq:
468
+ * breakpoint.hit_value -> int
469
+ *
470
+ * Returns the hit value of the breakpoint.
471
+ */
472
+ static VALUE
473
+ breakpoint_hit_value(VALUE self)
474
+ {
475
+ debug_breakpoint_t *breakpoint;
476
+
477
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
478
+ return INT2FIX(breakpoint->hit_value);
479
+ }
480
+
481
+ /*
482
+ * call-seq:
483
+ * breakpoint.hit_value = int
484
+ *
485
+ * Sets the hit value of the breakpoint.
486
+ */
487
+ static VALUE
488
+ breakpoint_set_hit_value(VALUE self, VALUE value)
489
+ {
490
+ debug_breakpoint_t *breakpoint;
491
+
492
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
493
+ breakpoint->hit_value = FIX2INT(value);
494
+ return value;
495
+ }
496
+
497
+ /*
498
+ * call-seq:
499
+ * breakpoint.hit_condition -> symbol
500
+ *
501
+ * Returns the hit condition of the breakpoint:
502
+ *
503
+ * +nil+ if it is an unconditional breakpoint, or
504
+ * :greater_or_equal, :equal, :modulo
505
+ */
506
+ static VALUE
507
+ breakpoint_hit_condition(VALUE self)
508
+ {
509
+ debug_breakpoint_t *breakpoint;
510
+
511
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
512
+ switch(breakpoint->hit_condition)
513
+ {
514
+ case HIT_COND_GE:
515
+ return ID2SYM(rb_intern("greater_or_equal"));
516
+ case HIT_COND_EQ:
517
+ return ID2SYM(rb_intern("equal"));
518
+ case HIT_COND_MOD:
519
+ return ID2SYM(rb_intern("modulo"));
520
+ case HIT_COND_NONE:
521
+ default:
522
+ return Qnil;
523
+ }
524
+ }
525
+
526
+ /*
527
+ * call-seq:
528
+ * breakpoint.hit_condition = symbol
529
+ *
530
+ * Sets the hit condition of the breakpoint which must be one of the following values:
531
+ *
532
+ * +nil+ if it is an unconditional breakpoint, or
533
+ * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
534
+ */
535
+ static VALUE
536
+ breakpoint_set_hit_condition(VALUE self, VALUE value)
537
+ {
538
+ debug_breakpoint_t *breakpoint;
539
+ ID id_value;
540
+
541
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
542
+ id_value = rb_to_id(value);
543
+
544
+ if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
545
+ breakpoint->hit_condition = HIT_COND_GE;
546
+ else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
547
+ breakpoint->hit_condition = HIT_COND_EQ;
548
+ else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
549
+ breakpoint->hit_condition = HIT_COND_MOD;
550
+ else
551
+ rb_raise(rb_eArgError, "Invalid condition parameter");
552
+ return value;
553
+ }
554
+
555
+ /*
556
+ * Document-class: Breakpoint
557
+ *
558
+ * == Summary
559
+ *
560
+ * This class represents a breakpoint. It defines position of the breakpoint and
561
+ * condition when this breakpoint should be triggered.
562
+ */
563
+ void
564
+ Init_breakpoint()
565
+ {
566
+ cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
567
+ rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1);
568
+ rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0);
569
+ rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
570
+ rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1);
571
+ rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0);
572
+ rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1);
573
+ rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0);
574
+ rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0);
575
+ rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1);
576
+ rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
577
+ rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
578
+ rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1);
579
+ rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
580
+ rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1);
581
+ idEval = rb_intern("eval");
582
+ rdebug_catchpoints = rb_hash_new();
583
+
584
+ }
585
+
586
+