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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -1
- data/GUIDE.md +14 -22
- data/README.md +69 -6
- data/bin/byebug +3 -20
- data/ext/byebug/breakpoint.c +185 -101
- data/ext/byebug/byebug.c +393 -214
- data/ext/byebug/byebug.h +34 -15
- data/ext/byebug/context.c +327 -102
- data/ext/byebug/extconf.rb +1 -1
- data/ext/byebug/locker.c +54 -0
- data/ext/byebug/threads.c +113 -0
- data/lib/byebug.rb +19 -58
- data/lib/byebug/command.rb +18 -19
- data/lib/byebug/commands/breakpoints.rb +1 -4
- data/lib/byebug/commands/catchpoint.rb +1 -1
- data/lib/byebug/commands/condition.rb +1 -1
- data/lib/byebug/commands/control.rb +2 -3
- data/lib/byebug/commands/display.rb +2 -7
- data/lib/byebug/commands/edit.rb +1 -1
- data/lib/byebug/commands/enable.rb +12 -12
- data/lib/byebug/commands/eval.rb +4 -4
- data/lib/byebug/commands/finish.rb +1 -1
- data/lib/byebug/commands/frame.rb +12 -8
- data/lib/byebug/commands/info.rb +20 -52
- data/lib/byebug/commands/kill.rb +1 -5
- data/lib/byebug/commands/list.rb +2 -1
- data/lib/byebug/commands/quit.rb +1 -1
- data/lib/byebug/commands/repl.rb +2 -2
- data/lib/byebug/commands/save.rb +1 -1
- data/lib/byebug/commands/set.rb +84 -90
- data/lib/byebug/commands/show.rb +44 -53
- data/lib/byebug/commands/skip.rb +1 -1
- data/lib/byebug/commands/stepping.rb +5 -4
- data/lib/byebug/commands/threads.rb +202 -0
- data/lib/byebug/commands/trace.rb +1 -1
- data/lib/byebug/helper.rb +3 -3
- data/lib/byebug/interface.rb +2 -20
- data/lib/byebug/processor.rb +21 -100
- data/lib/byebug/remote.rb +3 -3
- data/lib/byebug/version.rb +1 -1
- data/old_doc/byebug.1 +0 -6
- data/old_doc/byebug.texi +29 -46
- data/test/breakpoints_test.rb +44 -65
- data/test/conditions_test.rb +0 -9
- data/test/continue_test.rb +2 -2
- data/test/display_test.rb +4 -23
- data/test/edit_test.rb +2 -16
- data/test/eval_test.rb +4 -13
- data/test/examples/thread.rb +32 -0
- data/test/finish_test.rb +1 -13
- data/test/frame_test.rb +5 -12
- data/test/help_test.rb +2 -12
- data/test/info_test.rb +8 -18
- data/test/kill_test.rb +1 -10
- data/test/list_test.rb +5 -14
- data/test/method_test.rb +1 -10
- data/test/post_mortem_test.rb +247 -14
- data/test/quit_test.rb +0 -9
- data/test/reload_test.rb +1 -15
- data/test/repl_test.rb +1 -9
- data/test/restart_test.rb +3 -18
- data/test/save_test.rb +1 -13
- data/test/set_test.rb +35 -32
- data/test/show_test.rb +8 -27
- data/test/source_test.rb +1 -8
- data/test/stepping_test.rb +65 -96
- data/test/support/test_dsl.rb +12 -17
- data/test/test_helper.rb +1 -1
- data/test/thread_test.rb +106 -0
- data/test/trace_test.rb +5 -17
- data/test/variables_test.rb +1 -10
- metadata +9 -7
- data/lib/byebug/commands/jump.rb +0 -52
- data/test/jump_test.rb +0 -77
- data/test/support/context.rb +0 -15
data/ext/byebug/byebug.c
CHANGED
@@ -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
|
-
|
15
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
54
|
-
|
30
|
+
static void
|
31
|
+
trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc)
|
55
32
|
{
|
56
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
228
|
+
call_event(VALUE trace_point, void *data)
|
222
229
|
{
|
223
|
-
EVENT_SETUP
|
224
|
-
|
225
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
281
|
+
c_call_event(VALUE trace_point, void *data)
|
256
282
|
{
|
257
|
-
EVENT_SETUP
|
283
|
+
EVENT_SETUP
|
284
|
+
|
258
285
|
dc->stack_size++;
|
259
|
-
|
286
|
+
|
287
|
+
EVENT_COMMON
|
260
288
|
|
261
289
|
cleanup(dc);
|
262
290
|
}
|
263
291
|
|
264
292
|
static void
|
265
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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("@
|
310
|
-
rb_ivar_set(err, rb_intern("@
|
311
|
-
rb_ivar_set(err, rb_intern("@
|
312
|
-
rb_ivar_set(err, rb_intern("@
|
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
|
-
|
426
|
+
bb_contexts(VALUE self)
|
353
427
|
{
|
354
|
-
|
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
|
-
|
357
|
-
catchpoints = rb_hash_new();
|
358
|
-
context = context_create();
|
435
|
+
check_started();
|
359
436
|
|
360
|
-
|
361
|
-
|
362
|
-
process_line_event, NULL);
|
437
|
+
new_list = rb_ary_new();
|
438
|
+
list = rb_funcall(rb_cThread, rb_intern("list"), 0);
|
363
439
|
|
364
|
-
|
365
|
-
|
366
|
-
|
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
|
-
|
369
|
-
|
370
|
-
process_c_call_event, NULL);
|
447
|
+
threads_clear(threads);
|
448
|
+
Data_Get_Struct(threads, threads_table_t, t_tbl);
|
371
449
|
|
372
|
-
|
373
|
-
|
374
|
-
|
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
|
-
|
377
|
-
|
378
|
-
|
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
|
-
|
381
|
-
RUBY_EVENT_RAISE,
|
382
|
-
process_raise_event, NULL);
|
471
|
+
check_started();
|
383
472
|
|
384
|
-
|
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
|
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
|
-
|
486
|
+
bb_current_context(VALUE self)
|
396
487
|
{
|
397
|
-
|
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
|
-
|
405
|
-
breakpoints = Qnil;
|
406
|
-
catchpoints = Qnil;
|
490
|
+
check_started();
|
407
491
|
|
408
|
-
|
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
|
-
|
504
|
+
bb_started(VALUE self)
|
413
505
|
{
|
414
|
-
return
|
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
|
-
|
517
|
+
bb_stop(VALUE self)
|
419
518
|
{
|
420
|
-
if (
|
519
|
+
if (IS_STARTED)
|
421
520
|
{
|
422
|
-
|
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
|
-
|
547
|
+
bb_start(VALUE self)
|
430
548
|
{
|
431
549
|
VALUE result;
|
432
550
|
|
433
|
-
if (
|
551
|
+
if (IS_STARTED)
|
434
552
|
result = Qfalse;
|
435
553
|
else
|
436
554
|
{
|
437
|
-
|
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,
|
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
|
-
|
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,
|
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
|
-
|
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 (
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(&
|
795
|
+
rb_global_variable(&tracepoints);
|
796
|
+
rb_global_variable(&threads);
|
618
797
|
}
|