byebug 1.8.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }