byebug 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +4 -0
  2. data/.travis.yml +0 -5
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +1 -1
  5. data/LICENSE +23 -20
  6. data/byebug.gemspec +5 -5
  7. data/ext/byebug/breakpoint.c +102 -134
  8. data/ext/byebug/byebug.c +110 -64
  9. data/ext/byebug/byebug.h +2 -3
  10. data/ext/byebug/context.c +72 -39
  11. data/lib/byebug.rb +34 -38
  12. data/lib/byebug/command.rb +19 -24
  13. data/lib/byebug/commands/breakpoints.rb +11 -12
  14. data/lib/byebug/commands/catchpoint.rb +1 -1
  15. data/lib/byebug/commands/control.rb +2 -4
  16. data/lib/byebug/commands/finish.rb +1 -1
  17. data/lib/byebug/commands/frame.rb +15 -17
  18. data/lib/byebug/commands/info.rb +29 -28
  19. data/lib/byebug/commands/irb.rb +23 -21
  20. data/lib/byebug/commands/method.rb +4 -4
  21. data/lib/byebug/commands/reload.rb +8 -6
  22. data/lib/byebug/commands/set.rb +27 -23
  23. data/lib/byebug/commands/show.rb +6 -4
  24. data/lib/byebug/commands/stepping.rb +2 -2
  25. data/lib/byebug/commands/threads.rb +10 -10
  26. data/lib/byebug/commands/trace.rb +13 -14
  27. data/lib/byebug/commands/variables.rb +14 -12
  28. data/lib/byebug/context.rb +2 -15
  29. data/lib/byebug/interface.rb +5 -0
  30. data/lib/byebug/processor.rb +59 -64
  31. data/lib/byebug/version.rb +2 -1
  32. data/old_doc/Makefile +20 -0
  33. data/{man/rdebug.1 → old_doc/byebug.1} +5 -5
  34. data/old_doc/byebug.html +6178 -0
  35. data/old_doc/byebug.texi +3775 -0
  36. data/{doc → old_doc}/hanoi.rb +0 -0
  37. data/{doc → old_doc}/primes.rb +0 -0
  38. data/{doc → old_doc}/test-tri2.rb +0 -0
  39. data/{doc → old_doc}/tri3.rb +0 -0
  40. data/{doc → old_doc}/triangle.rb +0 -0
  41. data/test/breakpoints_test.rb +96 -60
  42. data/test/conditions_test.rb +15 -12
  43. data/test/examples/info.rb +5 -5
  44. data/test/examples/stepping.rb +1 -1
  45. data/test/frame_test.rb +40 -39
  46. data/test/info_test.rb +105 -96
  47. data/test/irb_test.rb +66 -61
  48. data/test/jump_test.rb +18 -9
  49. data/test/list_test.rb +114 -107
  50. data/test/restart_test.rb +51 -58
  51. data/test/save_test.rb +8 -7
  52. data/test/set_test.rb +8 -11
  53. data/test/show_test.rb +3 -5
  54. data/test/stepping_test.rb +43 -53
  55. data/test/support/context.rb +1 -0
  56. data/test/support/processor.rb +10 -4
  57. data/test/support/test_dsl.rb +46 -18
  58. data/test/support/test_interface.rb +8 -5
  59. data/test/test_helper.rb +2 -2
  60. data/test/trace_test.rb +123 -124
  61. metadata +39 -17
  62. data/AUTHORS +0 -10
  63. data/doc/rdebug-emacs.texi +0 -1030
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  tmp
2
+ pkg
2
3
  vendor/bundle
4
+ doc
3
5
 
4
6
  .rvmrc
5
7
  .gdbinit
@@ -8,3 +10,5 @@ vendor/bundle
8
10
  .tags
9
11
 
10
12
  Gemfile.lock
13
+
14
+ lib/byebug.so
@@ -1,8 +1,3 @@
1
1
  before_script: rake compile
2
2
  rvm:
3
- - 1.9.2
4
- - 1.9.3
5
3
  - 2.0.0
6
- matrix:
7
- allow_failures:
8
- - rvm: 2.0.0
@@ -1,2 +1,8 @@
1
1
  ## 0.0.1
2
+
2
3
  * Initial release
4
+
5
+
6
+ ## 1.0.0
7
+
8
+ * Green test suite
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/LICENSE CHANGED
@@ -1,20 +1,23 @@
1
- Copyright (c) 2013 David Rodríguez
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (C) 2013 David Rodríguez <deivid.rodriguez@gmail.com>
2
+ All rights reserved.
3
+ *
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ *
13
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
+ SUCH DAMAGE.
@@ -5,7 +5,7 @@ require File.dirname(__FILE__) + "/lib/byebug/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = %q{byebug}
7
7
  s.version = Byebug::VERSION
8
- s.authors = ["David Rodríguez"]
8
+ s.authors = ["David Rodríguez", "Kent Sibilev", "Mark Moseley"]
9
9
  s.email = "deivid.rodriguez@mail.com"
10
10
  s.homepage = "http://github.com/deivid-rodriguez/byebug"
11
11
  s.summary = %q{Ruby 2.0 fast debugger - base + cli}
@@ -13,17 +13,17 @@ Gem::Specification.new do |s|
13
13
  Ruby 2.0 TracePoint C API. The C extension was forked from debase whereas
14
14
  the rest of the gem was forked from debugger. The core component provides
15
15
  support that front-ends can build on. It provides breakpoint handling,
16
- bindings for stack frames among other things.
17
- }
16
+ bindings for stack frames among other things.}
18
17
  s.required_rubygems_version = ">= 1.3.6"
19
18
  s.extra_rdoc_files = [ "README.md" ]
20
19
  s.files = `git ls-files`.split("\n")
21
20
  s.extensions << "ext/byebug/extconf.rb"
22
21
  s.executables = ["byebug"]
23
- s.add_dependency "columnize", ">= 0.3.1"
22
+ s.add_dependency "columnize", "~> 0.3.6"
24
23
  s.add_dependency "debugger-linecache", '~> 1.2.0'
25
24
  s.add_development_dependency 'rake', '~> 10.0.3'
26
25
  s.add_development_dependency 'rake-compiler', '~> 0.8.3'
27
26
  s.add_development_dependency 'mocha', '~> 0.13.3'
28
- s.license = "MIT"
27
+ s.add_development_dependency 'minitest', '~> 4.7.0'
28
+ s.license = "BSD"
29
29
  end
@@ -21,34 +21,6 @@ eval_expression(VALUE args)
21
21
  return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
22
22
  }
23
23
 
24
- extern VALUE
25
- catchpoint_hit_count(VALUE catchpoints, VALUE exception, VALUE *exception_name)
26
- {
27
- VALUE ancestors;
28
- VALUE expn_class;
29
- VALUE aclass;
30
- VALUE mod_name;
31
- VALUE hit_count;
32
- int i;
33
-
34
- if (catchpoints == Qnil /*|| st_get_num_entries(RHASH_TBL(rdebug_catchpoints)) == 0)*/)
35
- return Qnil;
36
- expn_class = rb_obj_class(exception);
37
- ancestors = rb_mod_ancestors(expn_class);
38
- for(i = 0; i < RARRAY_LEN(ancestors); i++)
39
- {
40
- aclass = rb_ary_entry(ancestors, i);
41
- mod_name = rb_mod_name(aclass);
42
- hit_count = rb_hash_aref(catchpoints, mod_name);
43
- if(hit_count != Qnil)
44
- {
45
- *exception_name = mod_name;
46
- return hit_count;
47
- }
48
- }
49
- return Qnil;
50
- }
51
-
52
24
  static VALUE
53
25
  Breakpoint_hit_count(VALUE self)
54
26
  {
@@ -81,41 +53,41 @@ Breakpoint_set_hit_value(VALUE self, VALUE value)
81
53
  static VALUE
82
54
  Breakpoint_hit_condition(VALUE self)
83
55
  {
84
- breakpoint_t *breakpoint;
56
+ breakpoint_t *breakpoint;
85
57
 
86
- Data_Get_Struct(self, breakpoint_t, breakpoint);
87
- switch(breakpoint->hit_condition)
88
- {
89
- case HIT_COND_GE:
90
- return ID2SYM(rb_intern("greater_or_equal"));
91
- case HIT_COND_EQ:
92
- return ID2SYM(rb_intern("equal"));
93
- case HIT_COND_MOD:
94
- return ID2SYM(rb_intern("modulo"));
95
- case HIT_COND_NONE:
96
- default:
97
- return Qnil;
98
- }
58
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
59
+ switch(breakpoint->hit_condition)
60
+ {
61
+ case HIT_COND_GE:
62
+ return ID2SYM(rb_intern("greater_or_equal"));
63
+ case HIT_COND_EQ:
64
+ return ID2SYM(rb_intern("equal"));
65
+ case HIT_COND_MOD:
66
+ return ID2SYM(rb_intern("modulo"));
67
+ case HIT_COND_NONE:
68
+ default:
69
+ return Qnil;
70
+ }
99
71
  }
100
72
 
101
73
  static VALUE
102
74
  Breakpoint_set_hit_condition(VALUE self, VALUE value)
103
75
  {
104
- breakpoint_t *breakpoint;
105
- ID id_value;
76
+ breakpoint_t *breakpoint;
77
+ ID id_value;
106
78
 
107
- Data_Get_Struct(self, breakpoint_t, breakpoint);
108
- id_value = rb_to_id(value);
109
-
110
- if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
111
- breakpoint->hit_condition = HIT_COND_GE;
112
- else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
113
- breakpoint->hit_condition = HIT_COND_EQ;
114
- else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
115
- breakpoint->hit_condition = HIT_COND_MOD;
116
- else
117
- rb_raise(rb_eArgError, "Invalid condition parameter");
118
- return value;
79
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
80
+ id_value = rb_to_id(value);
81
+
82
+ if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
83
+ breakpoint->hit_condition = HIT_COND_GE;
84
+ else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
85
+ breakpoint->hit_condition = HIT_COND_EQ;
86
+ else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
87
+ breakpoint->hit_condition = HIT_COND_MOD;
88
+ else
89
+ rb_raise(rb_eArgError, "Invalid condition parameter");
90
+ return value;
119
91
  }
120
92
 
121
93
  static void
@@ -153,6 +125,7 @@ Breakpoint_initialize(VALUE self, VALUE source, VALUE pos, VALUE expr)
153
125
  breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
154
126
  breakpoint->hit_count = 0;
155
127
  breakpoint->hit_value = 0;
128
+ breakpoint->hit_condition = HIT_COND_NONE;
156
129
 
157
130
  return Qnil;
158
131
  }
@@ -302,47 +275,45 @@ filename_cmp(VALUE source, char *file)
302
275
  #endif
303
276
  }
304
277
 
305
- /* XXX: Activate */
306
- /*
307
278
  static int
308
- check_breakpoint_hit_condition(VALUE breakpoint_object)
279
+ check_breakpoint_by_hit_condition(VALUE breakpoint_object)
309
280
  {
310
- breakpoint_t *breakpoint;
281
+ breakpoint_t *breakpoint;
311
282
 
312
- if (breakpoint == Qnil)
313
- return 0;
283
+ if (breakpoint_object == Qnil)
284
+ return 0;
285
+ Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
314
286
 
315
- Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
316
- breakpoint->hit_count++;
287
+ breakpoint->hit_count++;
317
288
 
318
- if (Qtrue != breakpoint->enabled)
319
- return 0;
320
- switch (breakpoint->hit_condition)
289
+ if (Qtrue != breakpoint->enabled)
290
+ return 0;
291
+
292
+ switch (breakpoint->hit_condition)
293
+ {
294
+ case HIT_COND_NONE:
295
+ return 1;
296
+ case HIT_COND_GE:
321
297
  {
322
- case HIT_COND_NONE:
323
- return 1;
324
- case HIT_COND_GE:
325
- {
326
- if (breakpoint->hit_count >= breakpoint->hit_value)
327
- return 1;
328
- break;
329
- }
330
- case HIT_COND_EQ:
331
- {
332
- if (breakpoint->hit_count == breakpoint->hit_value)
333
- return 1;
334
- break;
335
- }
336
- case HIT_COND_MOD:
337
- {
338
- if (breakpoint->hit_count % breakpoint->hit_value == 0)
339
- return 1;
340
- break;
341
- }
298
+ if (breakpoint->hit_count >= breakpoint->hit_value)
299
+ return 1;
300
+ break;
342
301
  }
343
- return 0;
302
+ case HIT_COND_EQ:
303
+ {
304
+ if (breakpoint->hit_count == breakpoint->hit_value)
305
+ return 1;
306
+ break;
307
+ }
308
+ case HIT_COND_MOD:
309
+ {
310
+ if (breakpoint->hit_count % breakpoint->hit_value == 0)
311
+ return 1;
312
+ break;
313
+ }
314
+ }
315
+ return 0;
344
316
  }
345
- */
346
317
 
347
318
  static int
348
319
  check_breakpoint_by_pos(VALUE breakpoint_object, char *file, int line)
@@ -352,6 +323,7 @@ check_breakpoint_by_pos(VALUE breakpoint_object, char *file, int line)
352
323
  if(breakpoint_object == Qnil)
353
324
  return 0;
354
325
  Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
326
+
355
327
  if (Qtrue != breakpoint->enabled)
356
328
  return 0;
357
329
  if(breakpoint->type != BP_POS_TYPE)
@@ -367,48 +339,43 @@ static int
367
339
  check_breakpoint_by_method(VALUE breakpoint_object, VALUE klass, ID mid,
368
340
  VALUE self)
369
341
  {
370
- breakpoint_t *breakpoint;
342
+ breakpoint_t *breakpoint;
371
343
 
372
- if (breakpoint_object == Qnil)
373
- return 0;
374
- Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
375
- if (!Qtrue == breakpoint->enabled)
376
- return 0;
377
- if (breakpoint->type != BP_METHOD_TYPE)
378
- return 0;
379
- if (breakpoint->pos.mid != mid)
380
- return 0;
381
- if (classname_cmp(breakpoint->source, klass))
382
- return 1;
383
- if ((rb_type(self) == T_CLASS) &&
384
- classname_cmp(breakpoint->source, self))
385
- return 1;
344
+ if (breakpoint_object == Qnil)
345
+ return 0;
346
+ Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
347
+
348
+ if (!Qtrue == breakpoint->enabled)
349
+ return 0;
350
+ if (breakpoint->type != BP_METHOD_TYPE)
351
+ return 0;
352
+ if (breakpoint->pos.mid != mid)
386
353
  return 0;
354
+ if (classname_cmp(breakpoint->source, klass))
355
+ return 1;
356
+ if ((rb_type(self) == T_CLASS) && classname_cmp(breakpoint->source, self))
357
+ return 1;
358
+ return 0;
387
359
  }
388
360
 
389
361
  static int
390
362
  check_breakpoint_by_expr(VALUE breakpoint_object, VALUE binding)
391
363
  {
392
- breakpoint_t *breakpoint;
393
- VALUE args, expr_result;
364
+ breakpoint_t *breakpoint;
365
+ VALUE args, expr_result;
394
366
 
395
- if (breakpoint_object == Qnil)
396
- return 0;
397
- Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
398
- if (Qtrue != breakpoint->enabled)
399
- return 0;
400
- if (NIL_P(breakpoint->expr))
401
- return 1;
402
- args = rb_ary_new3(2, breakpoint->expr, binding);
403
- expr_result = rb_protect(eval_expression, args, 0);
404
- return RTEST(expr_result);
405
- }
367
+ if (breakpoint_object == Qnil)
368
+ return 0;
369
+ Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
406
370
 
407
- //static VALUE
408
- //Breakpoint_find(VALUE self, VALUE breakpoints, VALUE source, VALUE pos, VALUE binding)
409
- //{
410
- // return breakpoint_find(breakpoints, source, pos, binding);
411
- //}
371
+ if (Qtrue != breakpoint->enabled)
372
+ return 0;
373
+ if (NIL_P(breakpoint->expr))
374
+ return 1;
375
+ args = rb_ary_new3(2, breakpoint->expr, binding);
376
+ expr_result = rb_protect(eval_expression, args, 0);
377
+ return RTEST(expr_result);
378
+ }
412
379
 
413
380
  extern VALUE
414
381
  find_breakpoint_by_pos(VALUE breakpoints, VALUE source, VALUE pos,
@@ -425,7 +392,8 @@ find_breakpoint_by_pos(VALUE breakpoints, VALUE source, VALUE pos,
425
392
  {
426
393
  breakpoint_object = rb_ary_entry(breakpoints, i);
427
394
  if ( check_breakpoint_by_pos(breakpoint_object, file, line) &&
428
- check_breakpoint_by_expr(breakpoint_object, binding) )
395
+ check_breakpoint_by_expr(breakpoint_object, binding) &&
396
+ check_breakpoint_by_hit_condition(breakpoint_object) )
429
397
  {
430
398
  return breakpoint_object;
431
399
  }
@@ -437,17 +405,18 @@ extern VALUE
437
405
  find_breakpoint_by_method(VALUE breakpoints, VALUE klass, ID mid, VALUE binding,
438
406
  VALUE self)
439
407
  {
440
- VALUE breakpoint_object;
441
- int i;
408
+ VALUE breakpoint_object;
409
+ int i;
442
410
 
443
- for(i = 0; i < RARRAY_LEN(breakpoints); i++)
444
- {
445
- breakpoint_object = rb_ary_entry(breakpoints, i);
446
- if ( check_breakpoint_by_method(breakpoint_object, klass, mid, self) &&
447
- check_breakpoint_by_expr(breakpoint_object, binding) )
448
- return breakpoint_object;
449
- }
450
- return Qnil;
411
+ for(i = 0; i < RARRAY_LEN(breakpoints); i++)
412
+ {
413
+ breakpoint_object = rb_ary_entry(breakpoints, i);
414
+ if ( check_breakpoint_by_method(breakpoint_object, klass, mid, self) &&
415
+ check_breakpoint_by_expr(breakpoint_object, binding) &&
416
+ check_breakpoint_by_hit_condition(breakpoint_object) )
417
+ return breakpoint_object;
418
+ }
419
+ return Qnil;
451
420
  }
452
421
 
453
422
  extern void
@@ -455,7 +424,6 @@ Init_breakpoint(VALUE mByebug)
455
424
  {
456
425
  breakpoint_max = 0;
457
426
  cBreakpoint = rb_define_class_under(mByebug, "Breakpoint", rb_cObject);
458
- /* rb_define_singleton_method(cBreakpoint, "find", Breakpoint_find, 4); */
459
427
  rb_define_singleton_method(cBreakpoint, "remove", Breakpoint_remove, 2);
460
428
  rb_define_method(cBreakpoint, "initialize", Breakpoint_initialize, 3);
461
429
  rb_define_method(cBreakpoint, "id", Breakpoint_id, 0);
@@ -4,8 +4,10 @@ static VALUE mByebug; /* Ruby Byebug Module object */
4
4
  static VALUE cContext;
5
5
  static VALUE cDebugThread;
6
6
 
7
- static VALUE debug = Qfalse;
8
- static VALUE locker = Qnil;
7
+ static VALUE tracing = Qfalse;
8
+ static VALUE debug = Qfalse;
9
+ static VALUE locker = Qnil;
10
+
9
11
  static VALUE contexts;
10
12
  static VALUE catchpoints;
11
13
  static VALUE breakpoints;
@@ -16,10 +18,6 @@ static VALUE tpReturn;
16
18
  static VALUE tpRaise;
17
19
 
18
20
  static VALUE idAlive;
19
- static VALUE idAtBreakpoint;
20
- static VALUE idAtCatchpoint;
21
- static VALUE idAtLine;
22
- static VALUE idAtTracing;
23
21
 
24
22
  static void
25
23
  print_debug_info(char *event, VALUE path, VALUE lineno, VALUE method_id,
@@ -87,9 +85,7 @@ check_start_processing(debug_context_t *context, VALUE thread)
87
85
 
88
86
  while(1)
89
87
  {
90
- /* halt execution of the current thread if the byebug
91
- is activated in another
92
- */
88
+ /* halt execution of the current thread if byebug is activated in another */
93
89
  while(locker != Qnil && locker != thread)
94
90
  {
95
91
  add_to_locked(thread);
@@ -140,11 +136,11 @@ static void
140
136
  call_at_line(debug_context_t *context, char *file, int line,
141
137
  VALUE context_object, VALUE path, VALUE lineno)
142
138
  {
143
- CTX_FL_UNSET(context, CTX_FL_STEPPED);
139
+ CTX_FL_UNSET(context, CTX_FL_ENABLE_BKPT);
144
140
  CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
145
141
  context->last_file = file;
146
142
  context->last_line = line;
147
- rb_funcall(context_object, idAtLine, 2, path, lineno);
143
+ rb_funcall(context_object, rb_intern("at_line"), 2, path, lineno);
148
144
  }
149
145
 
150
146
  static void
@@ -154,56 +150,62 @@ process_line_event(VALUE trace_point, void *data)
154
150
  VALUE context_object;
155
151
  VALUE breakpoint;
156
152
  debug_context_t *context;
157
- int moved;
153
+ int moved = 0;
158
154
 
159
155
  context_object = Byebug_current_context(mByebug);
160
156
  Data_Get_Struct(context_object, debug_context_t, context);
161
157
  if (!check_start_processing(context, rb_thread_current())) return;
162
158
 
163
- load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class,
164
- &binding, &self);
159
+ load_frame_info(
160
+ trace_point, &path, &lineno, &method_id, &defined_class, &binding, &self);
165
161
  if (debug == Qtrue)
166
- print_debug_info("line", path, lineno, method_id, defined_class,
167
- context->stack_size);
162
+ print_debug_info(
163
+ "line", path, lineno, method_id, defined_class, context->stack_size);
168
164
 
169
165
  update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
170
166
  defined_class, binding, self);
171
167
 
172
- moved = context->last_line != FIX2INT(lineno) || context->last_file == NULL ||
173
- strcmp(context->last_file, RSTRING_PTR(path)) != 0;
168
+ if (context->last_line != FIX2INT(lineno) || context->last_file == NULL ||
169
+ strcmp(context->last_file, RSTRING_PTR(path)))
170
+ {
171
+ CTX_FL_SET(context, CTX_FL_ENABLE_BKPT);
172
+ moved = 1;
173
+ }
174
174
 
175
- if (CTX_FL_TEST(context, CTX_FL_TRACING))
176
- rb_funcall(context_object, idAtTracing, 2, path, lineno);
175
+ if (RTEST(tracing))
176
+ rb_funcall(context_object, rb_intern("at_tracing"), 2, path, lineno);
177
177
 
178
178
  if (context->dest_frame == -1 || context->stack_size == context->dest_frame)
179
179
  {
180
- if (moved || !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE))
181
- context->stop_next--;
182
- if (context->stop_next < 0)
183
- context->stop_next = -1;
184
- if (moved || (CTX_FL_TEST(context, CTX_FL_STEPPED) && !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE)))
185
- {
186
- context->stop_line--;
187
- CTX_FL_UNSET(context, CTX_FL_STEPPED);
188
- }
180
+ if (moved || !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE)) {
181
+ context->stop_next = context->stop_next <= 0 ? -1 : context->stop_next-1;
182
+ context->stop_line = context->stop_line <= 0 ? -1 : context->stop_line-1;
183
+ }
189
184
  }
190
185
  else if (context->stack_size < context->dest_frame)
191
186
  {
192
187
  context->stop_next = 0;
193
188
  }
194
189
 
195
- breakpoint = find_breakpoint_by_pos(breakpoints, path, lineno, binding);
196
- if (context->stop_next == 0 || context->stop_line == 0 ||
197
- breakpoint != Qnil)
190
+ if (context->stop_next == 0 || context->stop_line == 0)
198
191
  {
199
192
  context->stop_reason = CTX_STOP_STEP;
193
+ reset_stepping_stop_points(context);
194
+ call_at_line(
195
+ context, RSTRING_PTR(path), FIX2INT(lineno), context_object, path, lineno);
196
+ }
197
+ else if (CTX_FL_TEST(context, CTX_FL_ENABLE_BKPT))
198
+ {
199
+ breakpoint = find_breakpoint_by_pos(breakpoints, path, lineno, binding);
200
200
  if (breakpoint != Qnil) {
201
- rb_funcall(context_object, idAtBreakpoint, 1, breakpoint);
201
+ context->stop_reason = CTX_STOP_BREAKPOINT;
202
+ reset_stepping_stop_points(context);
203
+ rb_funcall(context_object, rb_intern("at_breakpoint"), 1, breakpoint);
204
+ call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
205
+ path, lineno);
202
206
  }
203
- reset_stepping_stop_points(context);
204
- call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
205
- path, lineno);
206
207
  }
208
+
207
209
  cleanup(context);
208
210
  }
209
211
 
@@ -218,7 +220,7 @@ process_return_event(VALUE trace_point, void *data)
218
220
  Data_Get_Struct(context_object, debug_context_t, context);
219
221
  if (!check_start_processing(context, rb_thread_current())) return;
220
222
 
221
- if(context->stack_size == context->stop_frame)
223
+ if (context->stack_size == context->stop_frame)
222
224
  {
223
225
  context->stop_next = 1;
224
226
  context->stop_frame = 0;
@@ -230,9 +232,9 @@ process_return_event(VALUE trace_point, void *data)
230
232
  print_debug_info("return", path, lineno, method_id, defined_class,
231
233
  context->stack_size);
232
234
 
233
- // rb_funcall(context_object, idAtReturn, 2, path, lineno);
234
-
235
+ //rb_funcall(context_object, idAtReturn, 2, path, lineno);
235
236
  pop_frame(context_object);
237
+
236
238
  cleanup(context);
237
239
  }
238
240
 
@@ -262,7 +264,7 @@ process_call_event(VALUE trace_point, void *data)
262
264
  binding, self);
263
265
  if (breakpoint != Qnil) {
264
266
  context->stop_reason = CTX_STOP_BREAKPOINT;
265
- rb_funcall(context_object, idAtBreakpoint, 1, breakpoint);
267
+ rb_funcall(context_object, rb_intern("at_breakpoint"), 1, breakpoint);
266
268
  call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
267
269
  path, lineno);
268
270
  }
@@ -275,10 +277,11 @@ process_raise_event(VALUE trace_point, void *data)
275
277
  {
276
278
  VALUE path, lineno, method_id, defined_class, binding, self;
277
279
  VALUE context_object;
278
- VALUE hit_count;
279
- VALUE exception_name;
280
+ VALUE expn_class, aclass;
281
+ VALUE err = rb_errinfo();
282
+ VALUE ancestors;
280
283
  debug_context_t *context;
281
- int c_hit_count;
284
+ int i;
282
285
 
283
286
  context_object = Byebug_current_context(mByebug);
284
287
  Data_Get_Struct(context_object, debug_context_t, context);
@@ -289,28 +292,47 @@ process_raise_event(VALUE trace_point, void *data)
289
292
  update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
290
293
  defined_class, binding, self);
291
294
 
292
- if (catchpoint_hit_count(catchpoints, rb_errinfo(), &exception_name) != Qnil) {
293
- /* On 64-bit systems with gcc and -O2 there seems to be
294
- an optimization bug in running INT2FIX(FIX2INT...)..)
295
- So we do this in two steps.
296
- */
297
- c_hit_count = FIX2INT(rb_hash_aref(catchpoints, exception_name)) + 1;
298
- hit_count = INT2FIX(c_hit_count);
299
- rb_hash_aset(catchpoints, exception_name, hit_count);
300
- context->stop_reason = CTX_STOP_CATCHPOINT;
301
- rb_funcall(context_object, idAtCatchpoint, 1, rb_errinfo());
302
- call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
303
- path, lineno);
295
+ if (debug == Qtrue)
296
+ print_debug_info("call", path, lineno, method_id, defined_class,
297
+ context->stack_size);
298
+ expn_class = rb_obj_class(err);
299
+
300
+ if (catchpoints == Qnil ||
301
+ context->stack_size == 0 ||
302
+ CTX_FL_TEST(context, CTX_FL_CATCHING) ||
303
+ RHASH_TBL(catchpoints)->num_entries == 0) {
304
+ cleanup(context);
305
+ return;
306
+ }
307
+
308
+ ancestors = rb_mod_ancestors(expn_class);
309
+ for (i = 0; i < RARRAY_LEN(ancestors); i++) {
310
+ VALUE mod_name;
311
+ VALUE hit_count;
312
+
313
+ aclass = rb_ary_entry(ancestors, i);
314
+ mod_name = rb_mod_name(aclass);
315
+ hit_count = rb_hash_aref(catchpoints, mod_name);
316
+
317
+ if (hit_count != Qnil) {
318
+ /* increment exception */
319
+ rb_hash_aset(catchpoints, mod_name, INT2FIX(FIX2INT(hit_count) + 1));
320
+ context->stop_reason = CTX_STOP_CATCHPOINT;
321
+ rb_funcall(context_object, rb_intern("at_catchpoint"), 1, rb_errinfo());
322
+ call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
323
+ path, lineno);
324
+ break;
325
+ }
304
326
  }
305
327
 
306
328
  cleanup(context);
307
329
  }
308
330
 
309
-
310
331
  static VALUE
311
332
  Byebug_setup_tracepoints(VALUE self)
312
333
  {
313
334
  if (catchpoints != Qnil) return Qnil;
335
+
314
336
  contexts = rb_hash_new();
315
337
  breakpoints = rb_ary_new();
316
338
  catchpoints = rb_hash_new();
@@ -436,7 +458,18 @@ Byebug_load(int argc, VALUE *argv, VALUE self)
436
458
  return Qnil;
437
459
  }
438
460
 
461
+ static VALUE
462
+ Byebug_tracing(VALUE self)
463
+ {
464
+ return tracing;
465
+ }
439
466
 
467
+ static VALUE
468
+ Byebug_set_tracing(VALUE self, VALUE value)
469
+ {
470
+ tracing = RTEST(value) ? Qtrue : Qfalse;
471
+ return value;
472
+ }
440
473
 
441
474
  static VALUE
442
475
  Byebug_contexts(VALUE self)
@@ -467,34 +500,47 @@ Byebug_catchpoints(VALUE self)
467
500
  return catchpoints;
468
501
  }
469
502
 
503
+ static VALUE
504
+ Byebug_add_catchpoint(VALUE self, VALUE value)
505
+ {
506
+ if (TYPE(value) != T_STRING)
507
+ rb_raise(rb_eTypeError, "value of a catchpoint must be String");
508
+
509
+ rb_hash_aset(catchpoints, rb_str_dup(value), INT2FIX(0));
510
+ return value;
511
+ }
512
+
470
513
  /*
471
514
  * Document-class: Byebug
472
515
  *
473
516
  * == Summary
474
517
  *
475
- * This is a singleton class allows controlling the byebug. Use it to start/stop
518
+ * This is a singleton class allows controlling byebug. Use it to start/stop
476
519
  * byebug, set/remove breakpoints, etc.
477
520
  */
478
521
  void
479
522
  Init_byebug()
480
523
  {
481
524
  mByebug = rb_define_module("Byebug");
482
- rb_define_module_function(mByebug, "setup_tracepoints", Byebug_setup_tracepoints, 0);
483
- rb_define_module_function(mByebug, "remove_tracepoints", Byebug_remove_tracepoints, 0);
484
- rb_define_module_function(mByebug, "current_context", Byebug_current_context, 0);
525
+ rb_define_module_function(mByebug, "setup_tracepoints",
526
+ Byebug_setup_tracepoints, 0);
527
+ rb_define_module_function(mByebug, "remove_tracepoints",
528
+ Byebug_remove_tracepoints, 0);
529
+ rb_define_module_function(mByebug, "current_context",
530
+ Byebug_current_context, 0);
485
531
  rb_define_module_function(mByebug, "contexts", Byebug_contexts, 0);
486
532
  rb_define_module_function(mByebug, "breakpoints", Byebug_breakpoints, 0);
533
+ rb_define_module_function(mByebug, "add_catchpoint",
534
+ Byebug_add_catchpoint, 1);
487
535
  rb_define_module_function(mByebug, "catchpoints", Byebug_catchpoints, 0);
488
536
  rb_define_module_function(mByebug, "_start", Byebug_start, 0);
489
537
  rb_define_module_function(mByebug, "stop", Byebug_stop, 0);
490
538
  rb_define_module_function(mByebug, "started?", Byebug_started, 0);
539
+ rb_define_module_function(mByebug, "tracing", Byebug_tracing, 0);
540
+ rb_define_module_function(mByebug, "tracing=", Byebug_set_tracing, 1);
491
541
  rb_define_module_function(mByebug, "debug_load", Byebug_load, -1);
492
542
 
493
543
  idAlive = rb_intern("alive?");
494
- idAtBreakpoint = rb_intern("at_breakpoint");
495
- idAtCatchpoint = rb_intern("at_catchpoint");
496
- idAtTracing = rb_intern("at_tracing");
497
- idAtLine = rb_intern("at_line");
498
544
 
499
545
  cContext = Init_context(mByebug);
500
546