byebug 1.8.2 → 2.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/GUIDE.md +14 -22
  4. data/README.md +69 -6
  5. data/bin/byebug +3 -20
  6. data/ext/byebug/breakpoint.c +185 -101
  7. data/ext/byebug/byebug.c +393 -214
  8. data/ext/byebug/byebug.h +34 -15
  9. data/ext/byebug/context.c +327 -102
  10. data/ext/byebug/extconf.rb +1 -1
  11. data/ext/byebug/locker.c +54 -0
  12. data/ext/byebug/threads.c +113 -0
  13. data/lib/byebug.rb +19 -58
  14. data/lib/byebug/command.rb +18 -19
  15. data/lib/byebug/commands/breakpoints.rb +1 -4
  16. data/lib/byebug/commands/catchpoint.rb +1 -1
  17. data/lib/byebug/commands/condition.rb +1 -1
  18. data/lib/byebug/commands/control.rb +2 -3
  19. data/lib/byebug/commands/display.rb +2 -7
  20. data/lib/byebug/commands/edit.rb +1 -1
  21. data/lib/byebug/commands/enable.rb +12 -12
  22. data/lib/byebug/commands/eval.rb +4 -4
  23. data/lib/byebug/commands/finish.rb +1 -1
  24. data/lib/byebug/commands/frame.rb +12 -8
  25. data/lib/byebug/commands/info.rb +20 -52
  26. data/lib/byebug/commands/kill.rb +1 -5
  27. data/lib/byebug/commands/list.rb +2 -1
  28. data/lib/byebug/commands/quit.rb +1 -1
  29. data/lib/byebug/commands/repl.rb +2 -2
  30. data/lib/byebug/commands/save.rb +1 -1
  31. data/lib/byebug/commands/set.rb +84 -90
  32. data/lib/byebug/commands/show.rb +44 -53
  33. data/lib/byebug/commands/skip.rb +1 -1
  34. data/lib/byebug/commands/stepping.rb +5 -4
  35. data/lib/byebug/commands/threads.rb +202 -0
  36. data/lib/byebug/commands/trace.rb +1 -1
  37. data/lib/byebug/helper.rb +3 -3
  38. data/lib/byebug/interface.rb +2 -20
  39. data/lib/byebug/processor.rb +21 -100
  40. data/lib/byebug/remote.rb +3 -3
  41. data/lib/byebug/version.rb +1 -1
  42. data/old_doc/byebug.1 +0 -6
  43. data/old_doc/byebug.texi +29 -46
  44. data/test/breakpoints_test.rb +44 -65
  45. data/test/conditions_test.rb +0 -9
  46. data/test/continue_test.rb +2 -2
  47. data/test/display_test.rb +4 -23
  48. data/test/edit_test.rb +2 -16
  49. data/test/eval_test.rb +4 -13
  50. data/test/examples/thread.rb +32 -0
  51. data/test/finish_test.rb +1 -13
  52. data/test/frame_test.rb +5 -12
  53. data/test/help_test.rb +2 -12
  54. data/test/info_test.rb +8 -18
  55. data/test/kill_test.rb +1 -10
  56. data/test/list_test.rb +5 -14
  57. data/test/method_test.rb +1 -10
  58. data/test/post_mortem_test.rb +247 -14
  59. data/test/quit_test.rb +0 -9
  60. data/test/reload_test.rb +1 -15
  61. data/test/repl_test.rb +1 -9
  62. data/test/restart_test.rb +3 -18
  63. data/test/save_test.rb +1 -13
  64. data/test/set_test.rb +35 -32
  65. data/test/show_test.rb +8 -27
  66. data/test/source_test.rb +1 -8
  67. data/test/stepping_test.rb +65 -96
  68. data/test/support/test_dsl.rb +12 -17
  69. data/test/test_helper.rb +1 -1
  70. data/test/thread_test.rb +106 -0
  71. data/test/trace_test.rb +5 -17
  72. data/test/variables_test.rb +1 -10
  73. metadata +9 -7
  74. data/lib/byebug/commands/jump.rb +0 -52
  75. data/test/jump_test.rb +0 -77
  76. data/test/support/context.rb +0 -15
@@ -1,65 +1,101 @@
1
1
  #include <byebug.h>
2
2
 
3
3
  static VALUE mByebug; /* Ruby Byebug Module object */
4
- static VALUE cContext;
5
4
 
6
5
  static VALUE tracing = Qfalse;
7
6
  static VALUE post_mortem = Qfalse;
8
7
  static VALUE debug = Qfalse;
9
8
 
10
- static VALUE context = Qnil;
11
9
  static VALUE catchpoints = Qnil;
12
10
  static VALUE breakpoints = Qnil;
11
+ static VALUE tracepoints = Qnil;
13
12
 
14
- static VALUE tpLine = Qnil;
15
- static VALUE tpCall = Qnil;
16
- static VALUE tpCCall = Qnil;
17
- static VALUE tpReturn = Qnil;
18
- static VALUE tpCReturn = Qnil;
19
- static VALUE tpRaise = Qnil;
13
+ /* Implements thread syncronization, we must stop threads when debugging */
14
+ VALUE locker = Qnil;
20
15
 
21
- static VALUE
22
- tp_inspect(rb_trace_arg_t *trace_arg) {
23
- if (trace_arg) {
24
- VALUE event = rb_tracearg_event(trace_arg);
25
- if (ID2SYM(rb_intern("line")) == event ||
26
- ID2SYM(rb_intern("specified_line")) == event)
27
- {
28
- VALUE sym = rb_tracearg_method_id(trace_arg);
29
- if (NIL_P(sym)) sym = rb_str_new_cstr("<main>");
30
- return rb_sprintf("%"PRIsVALUE"@%"PRIsVALUE":%d in `%"PRIsVALUE"'",
31
- rb_tracearg_event(trace_arg),
32
- rb_tracearg_path(trace_arg),
33
- FIX2INT(rb_tracearg_lineno(trace_arg)),
34
- sym);
35
- }
36
- if (ID2SYM(rb_intern("call")) == event ||
37
- ID2SYM(rb_intern("c_call")) == event ||
38
- ID2SYM(rb_intern("return")) == event ||
39
- ID2SYM(rb_intern("c_return")) == event)
40
- return rb_sprintf("%"PRIsVALUE" `%"PRIsVALUE"'@%"PRIsVALUE":%d",
41
- rb_tracearg_event(trace_arg),
42
- rb_tracearg_method_id(trace_arg),
43
- rb_tracearg_path(trace_arg),
44
- FIX2INT(rb_tracearg_lineno(trace_arg)));
45
- return rb_sprintf("%"PRIsVALUE"@%"PRIsVALUE":%d",
46
- rb_tracearg_event(trace_arg),
47
- rb_tracearg_path(trace_arg),
48
- FIX2INT(rb_tracearg_lineno(trace_arg)));
16
+ /* Threads table */
17
+ VALUE threads = Qnil;
18
+ VALUE cThreadsTable;
19
+
20
+ #define IS_STARTED (catchpoints != Qnil)
21
+ static void
22
+ check_started()
23
+ {
24
+ if (!IS_STARTED)
25
+ {
26
+ rb_raise(rb_eRuntimeError, "Byebug is not started yet.");
49
27
  }
50
- return rb_sprintf("No info");
51
28
  }
52
29
 
53
- static VALUE
54
- Byebug_context(VALUE self)
30
+ static void
31
+ trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc)
55
32
  {
56
- return context;
33
+ if (trace_arg)
34
+ {
35
+ int i = 0;
36
+ VALUE path = rb_tracearg_path(trace_arg);
37
+ VALUE line = rb_tracearg_lineno(trace_arg);
38
+ VALUE event = rb_tracearg_event(trace_arg);
39
+ VALUE mid = rb_tracearg_method_id(trace_arg);
40
+ for (i=0; i<dc->stack_size; i++) putc('|', stderr);
41
+ fprintf(stderr, "[#%d] %s@%s:%d %s\n", dc->thnum,
42
+ rb_id2name(SYM2ID(event)), RSTRING_PTR(path), NUM2INT(line),
43
+ NIL_P(mid) ? "" : rb_id2name(SYM2ID(mid)));
44
+ }
57
45
  }
58
46
 
59
47
  static void
60
48
  cleanup(debug_context_t *dc)
61
49
  {
50
+ VALUE thread;
51
+
62
52
  dc->stop_reason = CTX_STOP_NONE;
53
+
54
+ /* checks for dead threads */
55
+ check_thread_contexts();
56
+
57
+ /* release a lock */
58
+ locker = Qnil;
59
+
60
+ /* let the next thread to run */
61
+ thread = remove_from_locked();
62
+ if (thread != Qnil)
63
+ rb_thread_run(thread);
64
+ }
65
+
66
+ #define EVENT_SETUP \
67
+ rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(trace_point); \
68
+ debug_context_t *dc; \
69
+ VALUE context; \
70
+ thread_context_lookup(rb_thread_current(), &context); \
71
+ Data_Get_Struct(context, debug_context_t, dc); \
72
+ if (debug == Qtrue) trace_print(trace_arg, dc); \
73
+
74
+ #define EVENT_COMMON if (!trace_common(trace_arg, dc)) { return; }
75
+
76
+ static int
77
+ trace_common(rb_trace_arg_t *trace_arg, debug_context_t *dc)
78
+ {
79
+ /* return if thread marked as 'ignored', like byebug's control thread */
80
+ if (CTX_FL_TEST(dc, CTX_FL_IGNORE))
81
+ {
82
+ cleanup(dc);
83
+ return 0;
84
+ }
85
+
86
+ halt_while_other_thread_is_active(dc);
87
+
88
+ /* Get the lock! */
89
+ locker = rb_thread_current();
90
+
91
+ /* Many events per line, but only *one* breakpoint */
92
+ if (dc->last_line != rb_tracearg_lineno(trace_arg) ||
93
+ dc->last_file != rb_tracearg_path(trace_arg))
94
+ {
95
+ CTX_FL_SET(dc, CTX_FL_ENABLE_BKPT);
96
+ }
97
+
98
+ return 1;
63
99
  }
64
100
 
65
101
  static void
@@ -71,6 +107,8 @@ save_current_position(debug_context_t *dc, VALUE file, VALUE line)
71
107
  CTX_FL_UNSET(dc, CTX_FL_FORCE_MOVE);
72
108
  }
73
109
 
110
+ /* Functions that return control to byebug after the different events */
111
+
74
112
  static VALUE
75
113
  call_at(VALUE context_obj, debug_context_t *dc, ID mid, int argc, VALUE a0,
76
114
  VALUE a1)
@@ -138,52 +176,21 @@ call_at_line_check(VALUE context_obj, debug_context_t *dc,
138
176
  call_at_line(context_obj, dc, file, line);
139
177
  }
140
178
 
141
- #define BYEBUG_STARTED (catchpoints != Qnil)
142
-
143
- #define EVENT_SETUP \
144
- rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(trace_point); \
145
- debug_context_t *dc; \
146
- if (!BYEBUG_STARTED) \
147
- rb_raise(rb_eRuntimeError, "Byebug not started yet!"); \
148
- Data_Get_Struct(context, debug_context_t, dc); \
149
- if (debug == Qtrue) \
150
- printf("%s (stack_size: %d)\n", \
151
- RSTRING_PTR(tp_inspect(trace_arg)), dc->stack_size); \
152
179
 
153
- #define EVENT_COMMON() \
154
- if (trace_common(trace_arg, dc) == 0) { return; }
155
-
156
- static int
157
- trace_common(rb_trace_arg_t *trace_arg, debug_context_t *dc)
158
- {
159
- /* ignore a skipped section of code */
160
- if (CTX_FL_TEST(dc, CTX_FL_SKIPPED))
161
- {
162
- cleanup(dc);
163
- return 0;
164
- }
165
-
166
- /* Many events per line, but only *one* breakpoint */
167
- if (dc->last_line != rb_tracearg_lineno(trace_arg) ||
168
- dc->last_file != rb_tracearg_path(trace_arg))
169
- {
170
- CTX_FL_SET(dc, CTX_FL_ENABLE_BKPT);
171
- }
172
-
173
- return 1;
174
- }
180
+ /* TracePoint API event handlers */
175
181
 
176
182
  static void
177
- process_line_event(VALUE trace_point, void *data)
183
+ line_event(VALUE trace_point, void *data)
178
184
  {
179
- EVENT_SETUP;
185
+ EVENT_SETUP
186
+
180
187
  VALUE breakpoint = Qnil;
181
188
  VALUE file = rb_tracearg_path(trace_arg);
182
189
  VALUE line = rb_tracearg_lineno(trace_arg);
183
190
  VALUE binding = rb_tracearg_binding(trace_arg);
184
191
  int moved = 0;
185
192
 
186
- EVENT_COMMON();
193
+ EVENT_COMMON
187
194
 
188
195
  if (dc->stack_size == 0) dc->stack_size++;
189
196
 
@@ -218,21 +225,40 @@ process_line_event(VALUE trace_point, void *data)
218
225
  }
219
226
 
220
227
  static void
221
- process_c_return_event(VALUE trace_point, void *data)
228
+ call_event(VALUE trace_point, void *data)
222
229
  {
223
- EVENT_SETUP;
224
- if (dc->stack_size > 0) dc->stack_size--;
225
- EVENT_COMMON();
230
+ EVENT_SETUP
231
+
232
+ dc->stack_size++;
233
+
234
+ EVENT_COMMON
235
+
236
+ VALUE breakpoint = Qnil;
237
+ VALUE klass = rb_tracearg_defined_class(trace_arg);
238
+ VALUE mid = SYM2ID(rb_tracearg_method_id(trace_arg));
239
+ VALUE binding = rb_tracearg_binding(trace_arg);
240
+ VALUE self = rb_tracearg_self(trace_arg);
241
+ VALUE file = rb_tracearg_path(trace_arg);
242
+ VALUE line = rb_tracearg_lineno(trace_arg);
243
+
244
+ breakpoint = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
245
+ if (breakpoint != Qnil)
246
+ {
247
+ call_at_breakpoint(context, dc, breakpoint);
248
+ call_at_line(context, dc, file, line);
249
+ }
226
250
 
227
251
  cleanup(dc);
228
252
  }
229
253
 
230
254
  static void
231
- process_return_event(VALUE trace_point, void *data)
255
+ return_event(VALUE trace_point, void *data)
232
256
  {
233
- EVENT_SETUP;
257
+ EVENT_SETUP
258
+
234
259
  if (dc->stack_size > 0) dc->stack_size--;
235
- EVENT_COMMON();
260
+
261
+ EVENT_COMMON
236
262
 
237
263
  if (dc->stack_size + 1 == dc->before_frame)
238
264
  {
@@ -252,52 +278,41 @@ process_return_event(VALUE trace_point, void *data)
252
278
  }
253
279
 
254
280
  static void
255
- process_c_call_event(VALUE trace_point, void *data)
281
+ c_call_event(VALUE trace_point, void *data)
256
282
  {
257
- EVENT_SETUP;
283
+ EVENT_SETUP
284
+
258
285
  dc->stack_size++;
259
- EVENT_COMMON();
286
+
287
+ EVENT_COMMON
260
288
 
261
289
  cleanup(dc);
262
290
  }
263
291
 
264
292
  static void
265
- process_call_event(VALUE trace_point, void *data)
293
+ c_return_event(VALUE trace_point, void *data)
266
294
  {
267
- EVENT_SETUP;
268
- dc->stack_size++;
269
- EVENT_COMMON();
295
+ EVENT_SETUP
270
296
 
271
- VALUE breakpoint = Qnil;
272
- VALUE klass = rb_tracearg_defined_class(trace_arg);
273
- VALUE mid = SYM2ID(rb_tracearg_method_id(trace_arg));
274
- VALUE binding = rb_tracearg_binding(trace_arg);
275
- VALUE self = rb_tracearg_self(trace_arg);
276
- VALUE file = rb_tracearg_path(trace_arg);
277
- VALUE line = rb_tracearg_lineno(trace_arg);
297
+ if (dc->stack_size > 0) dc->stack_size--;
278
298
 
279
- breakpoint =
280
- find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
281
- if (breakpoint != Qnil)
282
- {
283
- call_at_breakpoint(context, dc, breakpoint);
284
- call_at_line(context, dc, file, line);
285
- }
299
+ EVENT_COMMON
286
300
 
287
301
  cleanup(dc);
288
302
  }
289
303
 
290
304
  static void
291
- process_raise_event(VALUE trace_point, void *data)
305
+ raise_event(VALUE trace_point, void *data)
292
306
  {
293
307
  EVENT_SETUP
308
+
294
309
  VALUE expn_class, aclass;
295
310
  VALUE err = rb_errinfo();
296
311
  VALUE ancestors;
297
312
  int i;
298
313
  debug_context_t *new_dc;
299
314
 
300
- EVENT_COMMON();
315
+ EVENT_COMMON
301
316
 
302
317
  VALUE binding = rb_tracearg_binding(trace_arg);
303
318
  VALUE path = rb_tracearg_path(trace_arg);
@@ -306,10 +321,10 @@ process_raise_event(VALUE trace_point, void *data)
306
321
  if (post_mortem == Qtrue)
307
322
  {
308
323
  context = context_dup(dc);
309
- rb_ivar_set(err, rb_intern("@__debug_file") , path);
310
- rb_ivar_set(err, rb_intern("@__debug_line") , lineno);
311
- rb_ivar_set(err, rb_intern("@__debug_binding"), binding);
312
- rb_ivar_set(err, rb_intern("@__debug_context"), context);
324
+ rb_ivar_set(err, rb_intern("@__bb_file") , path);
325
+ rb_ivar_set(err, rb_intern("@__bb_line") , lineno);
326
+ rb_ivar_set(err, rb_intern("@__bb_binding"), binding);
327
+ rb_ivar_set(err, rb_intern("@__bb_context"), context);
313
328
 
314
329
  Data_Get_Struct(context, debug_context_t, new_dc);
315
330
  rb_debug_inspector_open(context_backtrace_set, (void *)new_dc);
@@ -348,121 +363,221 @@ process_raise_event(VALUE trace_point, void *data)
348
363
  cleanup(dc);
349
364
  }
350
365
 
366
+
367
+ /* Setup TracePoint functionality */
368
+
369
+ static void
370
+ register_tracepoints(VALUE self)
371
+ {
372
+ int i;
373
+ VALUE traces = tracepoints;
374
+
375
+ if (NIL_P(traces))
376
+ {
377
+ traces = rb_ary_new();
378
+
379
+ int line_msk = RUBY_EVENT_LINE;
380
+ int call_msk = RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS;
381
+ int return_msk = RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END;
382
+ int c_call_msk = RUBY_EVENT_C_CALL;
383
+ int c_return_msk = RUBY_EVENT_C_RETURN;
384
+ int raise_msk = RUBY_EVENT_RAISE;
385
+
386
+ VALUE tpLine = rb_tracepoint_new(Qnil, line_msk , line_event , 0);
387
+ VALUE tpCall = rb_tracepoint_new(Qnil, call_msk , call_event , 0);
388
+ VALUE tpReturn = rb_tracepoint_new(Qnil, return_msk , return_event , 0);
389
+ VALUE tpCCall = rb_tracepoint_new(Qnil, c_call_msk , c_call_event , 0);
390
+ VALUE tpCReturn = rb_tracepoint_new(Qnil, c_return_msk, c_return_event, 0);
391
+ VALUE tpRaise = rb_tracepoint_new(Qnil, raise_msk , raise_event , 0);
392
+
393
+ rb_ary_push(traces, tpLine);
394
+ rb_ary_push(traces, tpCall);
395
+ rb_ary_push(traces, tpReturn);
396
+ rb_ary_push(traces, tpCCall);
397
+ rb_ary_push(traces, tpCReturn);
398
+ rb_ary_push(traces, tpRaise);
399
+
400
+ tracepoints = traces;
401
+ }
402
+
403
+ for (i = 0; i < RARRAY_LEN(traces); i++)
404
+ rb_tracepoint_enable(rb_ary_entry(traces, i));
405
+ }
406
+
407
+ static void
408
+ clear_tracepoints(VALUE self)
409
+ {
410
+ int i;
411
+
412
+ for (i = RARRAY_LEN(tracepoints)-1; i >= 0; i--)
413
+ rb_tracepoint_disable(rb_ary_entry(tracepoints, i));
414
+ }
415
+
416
+
417
+ /* Byebug's Public API */
418
+
419
+ /*
420
+ * call-seq:
421
+ * Byebug.contexts -> array
422
+ *
423
+ * Returns an array of all contexts.
424
+ */
351
425
  static VALUE
352
- Byebug_setup_tracepoints(VALUE self)
426
+ bb_contexts(VALUE self)
353
427
  {
354
- if (catchpoints != Qnil) return Qnil;
428
+ volatile VALUE list;
429
+ volatile VALUE new_list;
430
+ VALUE context;
431
+ threads_table_t *t_tbl;
432
+ debug_context_t *dc;
433
+ int i;
355
434
 
356
- breakpoints = rb_ary_new();
357
- catchpoints = rb_hash_new();
358
- context = context_create();
435
+ check_started();
359
436
 
360
- tpLine = rb_tracepoint_new(Qnil,
361
- RUBY_EVENT_LINE,
362
- process_line_event, NULL);
437
+ new_list = rb_ary_new();
438
+ list = rb_funcall(rb_cThread, rb_intern("list"), 0);
363
439
 
364
- tpCall = rb_tracepoint_new(Qnil,
365
- RUBY_EVENT_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS,
366
- process_call_event, NULL);
440
+ for (i = 0; i < RARRAY_LEN(list); i++)
441
+ {
442
+ VALUE thread = rb_ary_entry(list, i);
443
+ thread_context_lookup(thread, &context);
444
+ rb_ary_push(new_list, context);
445
+ }
367
446
 
368
- tpCCall = rb_tracepoint_new(Qnil,
369
- RUBY_EVENT_C_CALL,
370
- process_c_call_event, NULL);
447
+ threads_clear(threads);
448
+ Data_Get_Struct(threads, threads_table_t, t_tbl);
371
449
 
372
- tpReturn = rb_tracepoint_new(Qnil,
373
- RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_END,
374
- process_return_event, NULL);
450
+ for (i = 0; i < RARRAY_LEN(new_list); i++)
451
+ {
452
+ context = rb_ary_entry(new_list, i);
453
+ Data_Get_Struct(context, debug_context_t, dc);
454
+ st_insert(t_tbl->tbl, dc->thread, context);
455
+ }
456
+
457
+ return new_list;
458
+ }
375
459
 
376
- tpCReturn = rb_tracepoint_new(Qnil,
377
- RUBY_EVENT_C_RETURN,
378
- process_c_return_event, NULL);
460
+ /*
461
+ * call-seq:
462
+ * Byebug.thread_context(thread) -> context
463
+ *
464
+ * Returns context of the thread passed as an argument.
465
+ */
466
+ static VALUE
467
+ bb_thread_context(VALUE self, VALUE thread)
468
+ {
469
+ VALUE context;
379
470
 
380
- tpRaise = rb_tracepoint_new(Qnil,
381
- RUBY_EVENT_RAISE,
382
- process_raise_event, NULL);
471
+ check_started();
383
472
 
384
- rb_tracepoint_enable(tpLine);
385
- rb_tracepoint_enable(tpCall);
386
- rb_tracepoint_enable(tpCCall);
387
- rb_tracepoint_enable(tpReturn);
388
- rb_tracepoint_enable(tpCReturn);
389
- rb_tracepoint_enable(tpRaise);
473
+ thread_context_lookup(thread, &context);
390
474
 
391
- return Qnil;
475
+ return context;
392
476
  }
393
477
 
478
+ /*
479
+ * call-seq:
480
+ * Byebug.current_context -> context
481
+ *
482
+ * Returns the current context.
483
+ * <i>Note:</i> Byebug.current_context.thread == Thread.current
484
+ */
394
485
  static VALUE
395
- Byebug_remove_tracepoints(VALUE self)
486
+ bb_current_context(VALUE self)
396
487
  {
397
- rb_tracepoint_disable(tpRaise);
398
- rb_tracepoint_disable(tpCReturn);
399
- rb_tracepoint_disable(tpReturn);
400
- rb_tracepoint_disable(tpCCall);
401
- rb_tracepoint_disable(tpCall);
402
- rb_tracepoint_disable(tpLine);
488
+ VALUE context;
403
489
 
404
- context = Qnil;
405
- breakpoints = Qnil;
406
- catchpoints = Qnil;
490
+ check_started();
407
491
 
408
- return Qnil;
492
+ thread_context_lookup(rb_thread_current(), &context);
493
+
494
+ return context;
409
495
  }
410
496
 
497
+ /*
498
+ * call-seq:
499
+ * Byebug.started? -> bool
500
+ *
501
+ * Returns +true+ byebug is started.
502
+ */
411
503
  static VALUE
412
- Byebug_started(VALUE self)
504
+ bb_started(VALUE self)
413
505
  {
414
- return BYEBUG_STARTED;
506
+ return IS_STARTED;
415
507
  }
416
508
 
509
+ /*
510
+ * call-seq:
511
+ * Byebug.stop -> bool
512
+ *
513
+ * This method disables byebug. It returns +true+ if byebug was already
514
+ * disabled, otherwise it returns +false+.
515
+ */
417
516
  static VALUE
418
- Byebug_stop(VALUE self)
517
+ bb_stop(VALUE self)
419
518
  {
420
- if (BYEBUG_STARTED)
519
+ if (IS_STARTED)
421
520
  {
422
- Byebug_remove_tracepoints(self);
521
+ clear_tracepoints(self);
522
+
523
+ breakpoints = Qnil;
524
+ catchpoints = Qnil;
525
+ threads = Qnil;
526
+
423
527
  return Qfalse;
424
528
  }
425
529
  return Qtrue;
426
530
  }
427
531
 
532
+ /*
533
+ * call-seq:
534
+ * Byebug.start_ -> bool
535
+ * Byebug.start_ { ... } -> bool
536
+ *
537
+ * This method is internal and activates the debugger. Use Byebug.start (from
538
+ * <tt>lib/byebug.rb</tt>) instead.
539
+ *
540
+ * The return value is the value of !Byebug.started? <i>before</i> issuing the
541
+ * +start+; That is, +true+ is returned, unless byebug was previously started.
542
+ *
543
+ * If a block is given, it starts byebug and yields to block. When the block
544
+ * is finished executing it stops the debugger with Byebug.stop method.
545
+ */
428
546
  static VALUE
429
- Byebug_start(VALUE self)
547
+ bb_start(VALUE self)
430
548
  {
431
549
  VALUE result;
432
550
 
433
- if (BYEBUG_STARTED)
551
+ if (IS_STARTED)
434
552
  result = Qfalse;
435
553
  else
436
554
  {
437
- Byebug_setup_tracepoints(self);
555
+ locker = Qnil;
556
+ breakpoints = rb_ary_new();
557
+ catchpoints = rb_hash_new();
558
+ threads = threads_create();
559
+
560
+ register_tracepoints(self);
438
561
  result = Qtrue;
439
562
  }
440
563
 
441
564
  if (rb_block_given_p())
442
- rb_ensure(rb_yield, self, Byebug_stop, self);
565
+ rb_ensure(rb_yield, self, bb_stop, self);
443
566
 
444
567
  return result;
445
568
  }
446
569
 
570
+ /*
571
+ * call-seq:
572
+ * Byebug.debug_load(file, stop = false) -> nil
573
+ *
574
+ * Same as Kernel#load but resets current context's frames.
575
+ * +stop+ parameter forces byebug to stop at the first line of code in +file+
576
+ */
447
577
  static VALUE
448
- set_current_skipped_status(VALUE status)
449
- {
450
- VALUE context_obj;
451
- debug_context_t *dc;
452
-
453
- context_obj = Byebug_context(mByebug);
454
- Data_Get_Struct(context_obj, debug_context_t, dc);
455
- if (status)
456
- CTX_FL_SET(dc, CTX_FL_SKIPPED);
457
- else
458
- CTX_FL_UNSET(dc, CTX_FL_SKIPPED);
459
- return Qnil;
460
- }
461
-
462
- static VALUE
463
- Byebug_load(int argc, VALUE *argv, VALUE self)
578
+ bb_load(int argc, VALUE *argv, VALUE self)
464
579
  {
465
- VALUE file, stop, context_obj;
580
+ VALUE file, stop, context;
466
581
  debug_context_t *dc;
467
582
  VALUE status = Qnil;
468
583
  int state = 0;
@@ -472,10 +587,11 @@ Byebug_load(int argc, VALUE *argv, VALUE self)
472
587
  stop = Qfalse;
473
588
  }
474
589
 
475
- Byebug_start(self);
590
+ bb_start(self);
591
+
592
+ context = bb_current_context(self);
593
+ Data_Get_Struct(context, debug_context_t, dc);
476
594
 
477
- context_obj = Byebug_context(self);
478
- Data_Get_Struct(context_obj, debug_context_t, dc);
479
595
  if (RTEST(stop)) dc->steps = 1;
480
596
 
481
597
  /* Reset stack size to ignore byebug's own frames */
@@ -497,6 +613,23 @@ Byebug_load(int argc, VALUE *argv, VALUE self)
497
613
  return status;
498
614
  }
499
615
 
616
+ static VALUE
617
+ set_current_skipped_status(VALUE status)
618
+ {
619
+ VALUE context;
620
+ debug_context_t *dc;
621
+
622
+ context = bb_current_context(mByebug);
623
+ Data_Get_Struct(context, debug_context_t, dc);
624
+
625
+ if (status)
626
+ CTX_FL_SET(dc, CTX_FL_SKIPPED);
627
+ else
628
+ CTX_FL_UNSET(dc, CTX_FL_SKIPPED);
629
+
630
+ return Qnil;
631
+ }
632
+
500
633
  static VALUE
501
634
  debug_at_exit_c(VALUE proc)
502
635
  {
@@ -506,7 +639,7 @@ debug_at_exit_c(VALUE proc)
506
639
  static void
507
640
  debug_at_exit_i(VALUE proc)
508
641
  {
509
- if (BYEBUG_STARTED)
642
+ if (IS_STARTED)
510
643
  {
511
644
  set_current_skipped_status(Qtrue);
512
645
  rb_ensure(debug_at_exit_c, proc, set_current_skipped_status, Qfalse);
@@ -515,56 +648,106 @@ debug_at_exit_i(VALUE proc)
515
648
  debug_at_exit_c(proc);
516
649
  }
517
650
 
651
+ /*
652
+ * call-seq:
653
+ * Byebug.debug_at_exit { block } -> proc
654
+ *
655
+ * Register <tt>at_exit</tt> hook which is escaped from byebug.
656
+ */
518
657
  static VALUE
519
- Byebug_at_exit(VALUE self)
658
+ bb_at_exit(VALUE self)
520
659
  {
521
660
  VALUE proc;
661
+
522
662
  if (!rb_block_given_p()) rb_raise(rb_eArgError, "called without a block");
663
+
523
664
  proc = rb_block_proc();
524
665
  rb_set_end_proc(debug_at_exit_i, proc);
525
666
  return proc;
526
667
  }
527
668
 
669
+ /*
670
+ * call-seq:
671
+ * Byebug.tracing -> bool
672
+ *
673
+ * Returns +true+ if global tracing is enabled.
674
+ */
528
675
  static VALUE
529
- Byebug_tracing(VALUE self)
676
+ bb_tracing(VALUE self)
530
677
  {
531
678
  return tracing;
532
679
  }
533
680
 
681
+ /*
682
+ * call-seq:
683
+ * Byebug.tracing = bool
684
+ *
685
+ * Sets the global tracing flag.
686
+ */
534
687
  static VALUE
535
- Byebug_set_tracing(VALUE self, VALUE value)
688
+ bb_set_tracing(VALUE self, VALUE value)
536
689
  {
537
690
  tracing = RTEST(value) ? Qtrue : Qfalse;
538
691
  return value;
539
692
  }
540
693
 
694
+ /*
695
+ * call-seq:
696
+ * Byebug.post_mortem? -> bool
697
+ *
698
+ * Returns +true+ if post-moterm debugging is enabled.
699
+ */
541
700
  static VALUE
542
- Byebug_post_mortem(VALUE self)
701
+ bb_post_mortem(VALUE self)
543
702
  {
544
703
  return post_mortem;
545
704
  }
546
705
 
706
+ /*
707
+ * call-seq:
708
+ * Byebug.post_mortem = bool
709
+ *
710
+ * Sets post-moterm flag.
711
+ */
547
712
  static VALUE
548
- Byebug_set_post_mortem(VALUE self, VALUE value)
713
+ bb_set_post_mortem(VALUE self, VALUE value)
549
714
  {
550
715
  post_mortem = RTEST(value) ? Qtrue : Qfalse;
551
716
  return value;
552
717
  }
553
718
 
719
+ /*
720
+ * call-seq:
721
+ * Byebug.breakpoints -> array
722
+ *
723
+ * Returns an array of breakpoints.
724
+ */
554
725
  static VALUE
555
- Byebug_breakpoints(VALUE self)
726
+ bb_breakpoints(VALUE self)
556
727
  {
557
728
  return breakpoints;
558
729
  }
559
730
 
731
+ /*
732
+ * call-seq:
733
+ * Byebug.catchpoints -> array
734
+ *
735
+ * Returns an array of catchpoints.
736
+ */
560
737
  static VALUE
561
- Byebug_catchpoints(VALUE self)
738
+ bb_catchpoints(VALUE self)
562
739
  {
563
740
  return catchpoints;
564
741
  }
565
742
 
743
+ /*
744
+ * call-seq:
745
+ * Byebug.add_catchpoint(exception) -> exception
746
+ *
747
+ * Adds a new exception to the catchpoints array.
748
+ */
566
749
  static VALUE
567
- Byebug_add_catchpoint(VALUE self, VALUE value)
750
+ bb_add_catchpoint(VALUE self, VALUE value)
568
751
  {
569
752
  if (TYPE(value) != T_STRING)
570
753
  rb_raise(rb_eTypeError, "value of a catchpoint must be String");
@@ -585,34 +768,30 @@ void
585
768
  Init_byebug()
586
769
  {
587
770
  mByebug = rb_define_module("Byebug");
588
- rb_define_module_function(mByebug, "setup_tracepoints",
589
- Byebug_setup_tracepoints, 0);
590
- rb_define_module_function(mByebug, "remove_tracepoints",
591
- Byebug_remove_tracepoints, 0);
592
- rb_define_module_function(mByebug, "context", Byebug_context, 0);
593
- rb_define_module_function(mByebug, "breakpoints", Byebug_breakpoints, 0);
594
- rb_define_module_function(mByebug, "add_catchpoint",
595
- Byebug_add_catchpoint, 1);
596
- rb_define_module_function(mByebug, "catchpoints", Byebug_catchpoints, 0);
597
- rb_define_module_function(mByebug, "_start", Byebug_start, 0);
598
- rb_define_module_function(mByebug, "stop", Byebug_stop, 0);
599
- rb_define_module_function(mByebug, "started?", Byebug_started, 0);
600
- rb_define_module_function(mByebug, "tracing?", Byebug_tracing, 0);
601
- rb_define_module_function(mByebug, "tracing=", Byebug_set_tracing, 1);
602
- rb_define_module_function(mByebug, "debug_load", Byebug_load, -1);
603
- rb_define_module_function(mByebug, "debug_at_exit", Byebug_at_exit, 0);
604
- rb_define_module_function(mByebug, "post_mortem?", Byebug_post_mortem, 0);
605
- rb_define_module_function(mByebug, "post_mortem=", Byebug_set_post_mortem, 1);
606
-
607
- cContext = Init_context(mByebug);
608
771
 
772
+ rb_define_module_function(mByebug, "add_catchpoint" , bb_add_catchpoint , 1);
773
+ rb_define_module_function(mByebug, "breakpoints" , bb_breakpoints , 0);
774
+ rb_define_module_function(mByebug, "catchpoints" , bb_catchpoints , 0);
775
+ rb_define_module_function(mByebug, "contexts" , bb_contexts , 0);
776
+ rb_define_module_function(mByebug, "current_context", bb_current_context, 0);
777
+ rb_define_module_function(mByebug, "debug_at_exit" , bb_at_exit , 0);
778
+ rb_define_module_function(mByebug, "debug_load" , bb_load , -1);
779
+ rb_define_module_function(mByebug, "post_mortem?" , bb_post_mortem , 0);
780
+ rb_define_module_function(mByebug, "post_mortem=" , bb_set_post_mortem, 1);
781
+ rb_define_module_function(mByebug, "_start" , bb_start , 0);
782
+ rb_define_module_function(mByebug, "started?" , bb_started , 0);
783
+ rb_define_module_function(mByebug, "stop" , bb_stop , 0);
784
+ rb_define_module_function(mByebug, "thread_context" , bb_thread_context , 1);
785
+ rb_define_module_function(mByebug, "tracing?" , bb_tracing , 0);
786
+ rb_define_module_function(mByebug, "tracing=" , bb_set_tracing , 1);
787
+
788
+ cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
789
+
790
+ Init_context(mByebug);
609
791
  Init_breakpoint(mByebug);
610
792
 
611
- context = Qnil;
612
- catchpoints = Qnil;
613
- breakpoints = Qnil;
614
-
615
793
  rb_global_variable(&breakpoints);
616
794
  rb_global_variable(&catchpoints);
617
- rb_global_variable(&context);
795
+ rb_global_variable(&tracepoints);
796
+ rb_global_variable(&threads);
618
797
  }