byebug 0.0.1 → 1.0.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.
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