runger_byebug 11.2.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 +7 -0
- data/CHANGELOG.md +954 -0
- data/CONTRIBUTING.md +58 -0
- data/GUIDE.md +1806 -0
- data/LICENSE +23 -0
- data/README.md +199 -0
- data/exe/byebug +6 -0
- data/ext/byebug/breakpoint.c +521 -0
- data/ext/byebug/byebug.c +900 -0
- data/ext/byebug/byebug.h +145 -0
- data/ext/byebug/context.c +687 -0
- data/ext/byebug/extconf.rb +12 -0
- data/ext/byebug/locker.c +96 -0
- data/ext/byebug/threads.c +241 -0
- data/lib/byebug/attacher.rb +48 -0
- data/lib/byebug/breakpoint.rb +94 -0
- data/lib/byebug/command.rb +111 -0
- data/lib/byebug/command_list.rb +34 -0
- data/lib/byebug/commands/break.rb +114 -0
- data/lib/byebug/commands/catch.rb +78 -0
- data/lib/byebug/commands/condition.rb +55 -0
- data/lib/byebug/commands/continue.rb +68 -0
- data/lib/byebug/commands/debug.rb +38 -0
- data/lib/byebug/commands/delete.rb +55 -0
- data/lib/byebug/commands/disable/breakpoints.rb +42 -0
- data/lib/byebug/commands/disable/display.rb +43 -0
- data/lib/byebug/commands/disable.rb +33 -0
- data/lib/byebug/commands/display.rb +66 -0
- data/lib/byebug/commands/down.rb +45 -0
- data/lib/byebug/commands/edit.rb +69 -0
- data/lib/byebug/commands/enable/breakpoints.rb +42 -0
- data/lib/byebug/commands/enable/display.rb +43 -0
- data/lib/byebug/commands/enable.rb +33 -0
- data/lib/byebug/commands/finish.rb +57 -0
- data/lib/byebug/commands/frame.rb +57 -0
- data/lib/byebug/commands/help.rb +64 -0
- data/lib/byebug/commands/history.rb +39 -0
- data/lib/byebug/commands/info/breakpoints.rb +65 -0
- data/lib/byebug/commands/info/display.rb +49 -0
- data/lib/byebug/commands/info/file.rb +80 -0
- data/lib/byebug/commands/info/line.rb +35 -0
- data/lib/byebug/commands/info/program.rb +49 -0
- data/lib/byebug/commands/info.rb +37 -0
- data/lib/byebug/commands/interrupt.rb +34 -0
- data/lib/byebug/commands/irb.rb +50 -0
- data/lib/byebug/commands/kill.rb +45 -0
- data/lib/byebug/commands/list.rb +159 -0
- data/lib/byebug/commands/method.rb +53 -0
- data/lib/byebug/commands/next.rb +40 -0
- data/lib/byebug/commands/pry.rb +41 -0
- data/lib/byebug/commands/quit.rb +42 -0
- data/lib/byebug/commands/restart.rb +64 -0
- data/lib/byebug/commands/save.rb +72 -0
- data/lib/byebug/commands/set.rb +79 -0
- data/lib/byebug/commands/show.rb +45 -0
- data/lib/byebug/commands/skip.rb +85 -0
- data/lib/byebug/commands/source.rb +40 -0
- data/lib/byebug/commands/step.rb +40 -0
- data/lib/byebug/commands/thread/current.rb +37 -0
- data/lib/byebug/commands/thread/list.rb +43 -0
- data/lib/byebug/commands/thread/resume.rb +45 -0
- data/lib/byebug/commands/thread/stop.rb +43 -0
- data/lib/byebug/commands/thread/switch.rb +46 -0
- data/lib/byebug/commands/thread.rb +34 -0
- data/lib/byebug/commands/tracevar.rb +54 -0
- data/lib/byebug/commands/undisplay.rb +51 -0
- data/lib/byebug/commands/untracevar.rb +36 -0
- data/lib/byebug/commands/up.rb +45 -0
- data/lib/byebug/commands/var/all.rb +41 -0
- data/lib/byebug/commands/var/args.rb +39 -0
- data/lib/byebug/commands/var/const.rb +49 -0
- data/lib/byebug/commands/var/global.rb +37 -0
- data/lib/byebug/commands/var/instance.rb +39 -0
- data/lib/byebug/commands/var/local.rb +39 -0
- data/lib/byebug/commands/var.rb +37 -0
- data/lib/byebug/commands/where.rb +64 -0
- data/lib/byebug/commands.rb +40 -0
- data/lib/byebug/context.rb +157 -0
- data/lib/byebug/core.rb +115 -0
- data/lib/byebug/errors.rb +29 -0
- data/lib/byebug/frame.rb +185 -0
- data/lib/byebug/helpers/bin.rb +47 -0
- data/lib/byebug/helpers/eval.rb +134 -0
- data/lib/byebug/helpers/file.rb +63 -0
- data/lib/byebug/helpers/frame.rb +75 -0
- data/lib/byebug/helpers/parse.rb +80 -0
- data/lib/byebug/helpers/path.rb +40 -0
- data/lib/byebug/helpers/reflection.rb +19 -0
- data/lib/byebug/helpers/string.rb +33 -0
- data/lib/byebug/helpers/thread.rb +67 -0
- data/lib/byebug/helpers/toggle.rb +62 -0
- data/lib/byebug/helpers/var.rb +70 -0
- data/lib/byebug/history.rb +130 -0
- data/lib/byebug/interface.rb +146 -0
- data/lib/byebug/interfaces/local_interface.rb +63 -0
- data/lib/byebug/interfaces/remote_interface.rb +50 -0
- data/lib/byebug/interfaces/script_interface.rb +33 -0
- data/lib/byebug/interfaces/test_interface.rb +67 -0
- data/lib/byebug/option_setter.rb +95 -0
- data/lib/byebug/printers/base.rb +68 -0
- data/lib/byebug/printers/plain.rb +44 -0
- data/lib/byebug/printers/texts/base.yml +115 -0
- data/lib/byebug/printers/texts/plain.yml +33 -0
- data/lib/byebug/processors/command_processor.rb +173 -0
- data/lib/byebug/processors/control_processor.rb +24 -0
- data/lib/byebug/processors/post_mortem_processor.rb +18 -0
- data/lib/byebug/processors/script_processor.rb +49 -0
- data/lib/byebug/remote/client.rb +57 -0
- data/lib/byebug/remote/server.rb +47 -0
- data/lib/byebug/remote.rb +85 -0
- data/lib/byebug/runner.rb +198 -0
- data/lib/byebug/setting.rb +79 -0
- data/lib/byebug/settings/autoirb.rb +29 -0
- data/lib/byebug/settings/autolist.rb +29 -0
- data/lib/byebug/settings/autopry.rb +29 -0
- data/lib/byebug/settings/autosave.rb +17 -0
- data/lib/byebug/settings/basename.rb +16 -0
- data/lib/byebug/settings/callstyle.rb +20 -0
- data/lib/byebug/settings/fullpath.rb +16 -0
- data/lib/byebug/settings/histfile.rb +20 -0
- data/lib/byebug/settings/histsize.rb +20 -0
- data/lib/byebug/settings/linetrace.rb +22 -0
- data/lib/byebug/settings/listsize.rb +21 -0
- data/lib/byebug/settings/post_mortem.rb +27 -0
- data/lib/byebug/settings/savefile.rb +20 -0
- data/lib/byebug/settings/stack_on_error.rb +15 -0
- data/lib/byebug/settings/width.rb +20 -0
- data/lib/byebug/source_file_formatter.rb +71 -0
- data/lib/byebug/subcommands.rb +54 -0
- data/lib/byebug/version.rb +8 -0
- data/lib/byebug.rb +3 -0
- metadata +194 -0
data/ext/byebug/byebug.c
ADDED
@@ -0,0 +1,900 @@
|
|
1
|
+
#include "byebug.h"
|
2
|
+
|
3
|
+
static VALUE mByebug; /* Ruby Byebug Module object */
|
4
|
+
|
5
|
+
static VALUE tracing = Qfalse;
|
6
|
+
static VALUE post_mortem = Qfalse;
|
7
|
+
static VALUE verbose = Qfalse;
|
8
|
+
|
9
|
+
static VALUE catchpoints = Qnil;
|
10
|
+
static VALUE breakpoints = Qnil;
|
11
|
+
static VALUE tracepoints = Qnil;
|
12
|
+
|
13
|
+
static VALUE raised_exception = Qnil;
|
14
|
+
|
15
|
+
static ID idPuts;
|
16
|
+
static ID idEmpty;
|
17
|
+
|
18
|
+
/* Hash table with active threads and their associated contexts */
|
19
|
+
VALUE threads = Qnil;
|
20
|
+
|
21
|
+
/*
|
22
|
+
* call-seq:
|
23
|
+
* Byebug.breakpoints -> array
|
24
|
+
*
|
25
|
+
* Returns an array of breakpoints.
|
26
|
+
*/
|
27
|
+
static VALUE
|
28
|
+
Breakpoints(VALUE self)
|
29
|
+
{
|
30
|
+
UNUSED(self);
|
31
|
+
|
32
|
+
if (NIL_P(breakpoints))
|
33
|
+
breakpoints = rb_ary_new();
|
34
|
+
|
35
|
+
return breakpoints;
|
36
|
+
}
|
37
|
+
|
38
|
+
/*
|
39
|
+
* call-seq:
|
40
|
+
* Byebug.catchpoints -> hash
|
41
|
+
*
|
42
|
+
* Returns the catchpoints hash.
|
43
|
+
*/
|
44
|
+
static VALUE
|
45
|
+
Catchpoints(VALUE self)
|
46
|
+
{
|
47
|
+
UNUSED(self);
|
48
|
+
|
49
|
+
return catchpoints;
|
50
|
+
}
|
51
|
+
|
52
|
+
/*
|
53
|
+
* call-seq:
|
54
|
+
* Byebug.raised_exception -> exception
|
55
|
+
*
|
56
|
+
* Returns raised exception when in post_mortem mode.
|
57
|
+
*/
|
58
|
+
static VALUE
|
59
|
+
Raised_exception(VALUE self)
|
60
|
+
{
|
61
|
+
UNUSED(self);
|
62
|
+
|
63
|
+
return raised_exception;
|
64
|
+
}
|
65
|
+
|
66
|
+
#define IS_STARTED (!NIL_P(catchpoints))
|
67
|
+
|
68
|
+
static void
|
69
|
+
check_started()
|
70
|
+
{
|
71
|
+
if (!IS_STARTED)
|
72
|
+
{
|
73
|
+
rb_raise(rb_eRuntimeError, "Byebug is not started yet.");
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
static void
|
78
|
+
trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc,
|
79
|
+
const char *file_filter, const char *debug_msg)
|
80
|
+
{
|
81
|
+
char *fullpath = NULL;
|
82
|
+
const char *basename;
|
83
|
+
int filtered = 0;
|
84
|
+
const char *event = rb_id2name(SYM2ID(rb_tracearg_event(trace_arg)));
|
85
|
+
|
86
|
+
VALUE rb_path = rb_tracearg_path(trace_arg);
|
87
|
+
const char *path = NIL_P(rb_path) ? "" : RSTRING_PTR(rb_path);
|
88
|
+
|
89
|
+
int line = NUM2INT(rb_tracearg_lineno(trace_arg));
|
90
|
+
|
91
|
+
VALUE rb_mid = rb_tracearg_method_id(trace_arg);
|
92
|
+
const char *mid = NIL_P(rb_mid) ? "(top level)" : rb_id2name(SYM2ID(rb_mid));
|
93
|
+
|
94
|
+
VALUE rb_cl = rb_tracearg_defined_class(trace_arg);
|
95
|
+
VALUE rb_cl_name = NIL_P(rb_cl) ? rb_cl : rb_mod_name(rb_cl);
|
96
|
+
const char *defined_class = NIL_P(rb_cl_name) ? "" : RSTRING_PTR(rb_cl_name);
|
97
|
+
|
98
|
+
if (!trace_arg)
|
99
|
+
return;
|
100
|
+
|
101
|
+
if (file_filter)
|
102
|
+
{
|
103
|
+
#ifndef _WIN32
|
104
|
+
fullpath = realpath(path, NULL);
|
105
|
+
#endif
|
106
|
+
basename = fullpath ? strrchr(fullpath, '/') : path;
|
107
|
+
|
108
|
+
if (!basename || strncmp(basename + 1, file_filter, strlen(file_filter)))
|
109
|
+
filtered = 1;
|
110
|
+
|
111
|
+
#ifndef _WIN32
|
112
|
+
free(fullpath);
|
113
|
+
#endif
|
114
|
+
}
|
115
|
+
|
116
|
+
if (!filtered)
|
117
|
+
{
|
118
|
+
if (debug_msg)
|
119
|
+
rb_funcall(mByebug, idPuts, 1,
|
120
|
+
rb_sprintf("[#%d] %s\n", dc->thnum, debug_msg));
|
121
|
+
else
|
122
|
+
rb_funcall(mByebug, idPuts, 1,
|
123
|
+
rb_sprintf("%*s [#%d] %s@%s:%d %s#%s\n", dc->calced_stack_size,
|
124
|
+
"", dc->thnum, event, path, line, defined_class,
|
125
|
+
mid));
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
static void
|
130
|
+
cleanup(debug_context_t *dc)
|
131
|
+
{
|
132
|
+
dc->stop_reason = CTX_STOP_NONE;
|
133
|
+
|
134
|
+
release_lock();
|
135
|
+
}
|
136
|
+
|
137
|
+
#define EVENT_TEARDOWN cleanup(dc);
|
138
|
+
|
139
|
+
#define EVENT_SETUP \
|
140
|
+
debug_context_t *dc; \
|
141
|
+
VALUE context; \
|
142
|
+
rb_trace_arg_t *trace_arg; \
|
143
|
+
\
|
144
|
+
UNUSED(data); \
|
145
|
+
\
|
146
|
+
if (!is_living_thread(rb_thread_current())) \
|
147
|
+
return; \
|
148
|
+
\
|
149
|
+
thread_context_lookup(rb_thread_current(), &context); \
|
150
|
+
Data_Get_Struct(context, debug_context_t, dc); \
|
151
|
+
\
|
152
|
+
trace_arg = rb_tracearg_from_tracepoint(trace_point); \
|
153
|
+
if (verbose == Qtrue) \
|
154
|
+
trace_print(trace_arg, dc, 0, 0); \
|
155
|
+
\
|
156
|
+
if (CTX_FL_TEST(dc, CTX_FL_IGNORE)) \
|
157
|
+
return; \
|
158
|
+
\
|
159
|
+
acquire_lock(dc);
|
160
|
+
|
161
|
+
|
162
|
+
#define CALL_EVENT_SETUP \
|
163
|
+
dc->calced_stack_size++; \
|
164
|
+
dc->steps_out = dc->steps_out < 0 ? -1 : dc->steps_out + 1;
|
165
|
+
|
166
|
+
#define RETURN_EVENT_SETUP \
|
167
|
+
dc->calced_stack_size--; \
|
168
|
+
\
|
169
|
+
if (dc->steps_out == 1) \
|
170
|
+
dc->steps = 1;
|
171
|
+
|
172
|
+
#define RETURN_EVENT_TEARDOWN \
|
173
|
+
dc->steps_out = dc->steps_out <= 0 ? -1 : dc->steps_out - 1;
|
174
|
+
|
175
|
+
|
176
|
+
/* Functions that return control to byebug after the different events */
|
177
|
+
|
178
|
+
static VALUE
|
179
|
+
call_at(VALUE ctx, debug_context_t *dc, ID mid, int argc, VALUE arg)
|
180
|
+
{
|
181
|
+
struct call_with_inspection_data cwi;
|
182
|
+
VALUE argv[1];
|
183
|
+
|
184
|
+
argv[0] = arg;
|
185
|
+
|
186
|
+
cwi.dc = dc;
|
187
|
+
cwi.ctx = ctx;
|
188
|
+
cwi.id = mid;
|
189
|
+
cwi.argc = argc;
|
190
|
+
cwi.argv = &argv[0];
|
191
|
+
|
192
|
+
return call_with_debug_inspector(&cwi);
|
193
|
+
}
|
194
|
+
|
195
|
+
static VALUE
|
196
|
+
call_at_line(VALUE ctx, debug_context_t *dc)
|
197
|
+
{
|
198
|
+
return call_at(ctx, dc, rb_intern("at_line"), 0, Qnil);
|
199
|
+
}
|
200
|
+
|
201
|
+
static VALUE
|
202
|
+
call_at_tracing(VALUE ctx, debug_context_t *dc)
|
203
|
+
{
|
204
|
+
return call_at(ctx, dc, rb_intern("at_tracing"), 0, Qnil);
|
205
|
+
}
|
206
|
+
|
207
|
+
static VALUE
|
208
|
+
call_at_breakpoint(VALUE ctx, debug_context_t *dc, VALUE breakpoint)
|
209
|
+
{
|
210
|
+
dc->stop_reason = CTX_STOP_BREAKPOINT;
|
211
|
+
|
212
|
+
return call_at(ctx, dc, rb_intern("at_breakpoint"), 1, breakpoint);
|
213
|
+
}
|
214
|
+
|
215
|
+
static VALUE
|
216
|
+
call_at_catchpoint(VALUE ctx, debug_context_t *dc, VALUE exp)
|
217
|
+
{
|
218
|
+
dc->stop_reason = CTX_STOP_CATCHPOINT;
|
219
|
+
|
220
|
+
return call_at(ctx, dc, rb_intern("at_catchpoint"), 1, exp);
|
221
|
+
}
|
222
|
+
|
223
|
+
static VALUE
|
224
|
+
call_at_return(VALUE ctx, debug_context_t *dc, VALUE return_value)
|
225
|
+
{
|
226
|
+
dc->stop_reason = CTX_STOP_BREAKPOINT;
|
227
|
+
|
228
|
+
return call_at(ctx, dc, rb_intern("at_return"), 1, return_value);
|
229
|
+
}
|
230
|
+
|
231
|
+
static VALUE
|
232
|
+
call_at_end(VALUE ctx, debug_context_t *dc)
|
233
|
+
{
|
234
|
+
dc->stop_reason = CTX_STOP_BREAKPOINT;
|
235
|
+
|
236
|
+
return call_at(ctx, dc, rb_intern("at_end"), 0, Qnil);
|
237
|
+
}
|
238
|
+
|
239
|
+
static void
|
240
|
+
call_at_line_check(VALUE ctx, debug_context_t *dc, VALUE breakpoint)
|
241
|
+
{
|
242
|
+
dc->stop_reason = CTX_STOP_STEP;
|
243
|
+
|
244
|
+
if (!NIL_P(breakpoint))
|
245
|
+
call_at_breakpoint(ctx, dc, breakpoint);
|
246
|
+
|
247
|
+
byebug_reset_stepping_stop_points(dc);
|
248
|
+
|
249
|
+
call_at_line(ctx, dc);
|
250
|
+
}
|
251
|
+
|
252
|
+
|
253
|
+
/* TracePoint API event handlers */
|
254
|
+
|
255
|
+
static void
|
256
|
+
line_event(VALUE trace_point, void *data)
|
257
|
+
{
|
258
|
+
VALUE brkpnt, file, line, binding;
|
259
|
+
|
260
|
+
EVENT_SETUP;
|
261
|
+
|
262
|
+
file = rb_tracearg_path(trace_arg);
|
263
|
+
line = rb_tracearg_lineno(trace_arg);
|
264
|
+
binding = rb_tracearg_binding(trace_arg);
|
265
|
+
|
266
|
+
if (RTEST(tracing))
|
267
|
+
call_at_tracing(context, dc);
|
268
|
+
|
269
|
+
if (!CTX_FL_TEST(dc, CTX_FL_IGNORE_STEPS))
|
270
|
+
dc->steps = dc->steps <= 0 ? -1 : dc->steps - 1;
|
271
|
+
|
272
|
+
if (dc->calced_stack_size <= dc->dest_frame)
|
273
|
+
{
|
274
|
+
dc->dest_frame = dc->calced_stack_size;
|
275
|
+
CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS);
|
276
|
+
|
277
|
+
dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1;
|
278
|
+
}
|
279
|
+
|
280
|
+
if (dc->steps == 0 || dc->lines == 0)
|
281
|
+
call_at_line_check(context, dc, Qnil);
|
282
|
+
else
|
283
|
+
{
|
284
|
+
brkpnt = Qnil;
|
285
|
+
|
286
|
+
if (!NIL_P(breakpoints))
|
287
|
+
brkpnt = find_breakpoint_by_pos(breakpoints, file, line, binding);
|
288
|
+
|
289
|
+
if (!NIL_P(brkpnt))
|
290
|
+
call_at_line_check(context, dc, brkpnt);
|
291
|
+
}
|
292
|
+
|
293
|
+
EVENT_TEARDOWN;
|
294
|
+
}
|
295
|
+
|
296
|
+
static void
|
297
|
+
call_event(VALUE trace_point, void *data)
|
298
|
+
{
|
299
|
+
VALUE brkpnt, klass, msym, mid, binding, self;
|
300
|
+
|
301
|
+
EVENT_SETUP;
|
302
|
+
|
303
|
+
if (dc->calced_stack_size <= dc->dest_frame)
|
304
|
+
CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS);
|
305
|
+
|
306
|
+
CALL_EVENT_SETUP;
|
307
|
+
|
308
|
+
msym = rb_tracearg_method_id(trace_arg);
|
309
|
+
|
310
|
+
mid = SYM2ID(msym);
|
311
|
+
klass = rb_tracearg_defined_class(trace_arg);
|
312
|
+
binding = rb_tracearg_binding(trace_arg);
|
313
|
+
self = rb_tracearg_self(trace_arg);
|
314
|
+
|
315
|
+
brkpnt = Qnil;
|
316
|
+
|
317
|
+
if (!NIL_P(breakpoints))
|
318
|
+
brkpnt = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
|
319
|
+
|
320
|
+
if (!NIL_P(brkpnt))
|
321
|
+
{
|
322
|
+
call_at_breakpoint(context, dc, brkpnt);
|
323
|
+
call_at_line(context, dc);
|
324
|
+
}
|
325
|
+
|
326
|
+
EVENT_TEARDOWN;
|
327
|
+
}
|
328
|
+
|
329
|
+
static void
|
330
|
+
return_event(VALUE trace_point, void *data)
|
331
|
+
{
|
332
|
+
VALUE brkpnt, file, line, binding;
|
333
|
+
|
334
|
+
EVENT_SETUP;
|
335
|
+
|
336
|
+
RETURN_EVENT_SETUP;
|
337
|
+
|
338
|
+
if ((dc->steps_out == 0) && (CTX_FL_TEST(dc, CTX_FL_STOP_ON_RET)))
|
339
|
+
{
|
340
|
+
byebug_reset_stepping_stop_points(dc);
|
341
|
+
|
342
|
+
call_at_return(context, dc, rb_tracearg_return_value(trace_arg));
|
343
|
+
}
|
344
|
+
else if (!NIL_P(breakpoints))
|
345
|
+
{
|
346
|
+
file = rb_tracearg_path(trace_arg);
|
347
|
+
/*
|
348
|
+
* @todo Sometimes the TracePoint API gives some return events without
|
349
|
+
* file:line information, so we need to guard for nil until we know what's
|
350
|
+
* going on. This happens, for example, with active_support core extensions:
|
351
|
+
*
|
352
|
+
* [#7] call@.../core_ext/numeric/conversions.rb:124 Fixnum#to_s
|
353
|
+
* [#7] b_call@.../core_ext/numeric/conversions.rb:124 BigDecimal#to_s
|
354
|
+
* [#7] line@.../core_ext/numeric/conversions.rb:125 BigDecimal#to_s
|
355
|
+
* [#7] c_call@.../core_ext/numeric/conversions.rb:125 Kernel#is_a?
|
356
|
+
* [#7] c_return@.../core_ext/numeric/conversions.rb:125 Kernel#is_a?
|
357
|
+
* [#7] line@.../core_ext/numeric/conversions.rb:131 BigDecimal#to_s
|
358
|
+
* [#7] c_call@.../core_ext/numeric/conversions.rb:131 Fixnum#to_default_s
|
359
|
+
* [#7] c_return@.../core_ext/numeric/conversions.rb:131 Fixnum#to_default_s
|
360
|
+
* [#7] b_return@/hort/core_ext/numeric/conversions.rb:133 BigDecimal#to_s
|
361
|
+
* [#7] return@:0 Fixnum#to_s # => This guy...
|
362
|
+
*/
|
363
|
+
if (NIL_P(file))
|
364
|
+
rb_warn("The TracePoint API emitted a return event without file information. It might be a bug, please report this.");
|
365
|
+
else
|
366
|
+
{
|
367
|
+
line = rb_tracearg_lineno(trace_arg);
|
368
|
+
binding = rb_tracearg_binding(trace_arg);
|
369
|
+
|
370
|
+
brkpnt = find_breakpoint_by_pos(breakpoints, file, line, binding);
|
371
|
+
|
372
|
+
if (!NIL_P(brkpnt))
|
373
|
+
call_at_return(context, dc, rb_tracearg_return_value(trace_arg));
|
374
|
+
}
|
375
|
+
}
|
376
|
+
|
377
|
+
RETURN_EVENT_TEARDOWN;
|
378
|
+
|
379
|
+
EVENT_TEARDOWN;
|
380
|
+
}
|
381
|
+
|
382
|
+
static void
|
383
|
+
end_event(VALUE trace_point, void *data)
|
384
|
+
{
|
385
|
+
EVENT_SETUP;
|
386
|
+
|
387
|
+
RETURN_EVENT_SETUP;
|
388
|
+
|
389
|
+
if ((dc->steps_out == 0) && (CTX_FL_TEST(dc, CTX_FL_STOP_ON_RET)))
|
390
|
+
{
|
391
|
+
byebug_reset_stepping_stop_points(dc);
|
392
|
+
|
393
|
+
call_at_end(context, dc);
|
394
|
+
}
|
395
|
+
|
396
|
+
RETURN_EVENT_TEARDOWN;
|
397
|
+
|
398
|
+
EVENT_TEARDOWN;
|
399
|
+
}
|
400
|
+
|
401
|
+
static void
|
402
|
+
raw_call_event(VALUE trace_point, void *data)
|
403
|
+
{
|
404
|
+
EVENT_SETUP;
|
405
|
+
|
406
|
+
CALL_EVENT_SETUP;
|
407
|
+
|
408
|
+
EVENT_TEARDOWN;
|
409
|
+
}
|
410
|
+
|
411
|
+
static void
|
412
|
+
raw_return_event(VALUE trace_point, void *data)
|
413
|
+
{
|
414
|
+
EVENT_SETUP;
|
415
|
+
|
416
|
+
RETURN_EVENT_SETUP;
|
417
|
+
|
418
|
+
RETURN_EVENT_TEARDOWN;
|
419
|
+
|
420
|
+
EVENT_TEARDOWN;
|
421
|
+
}
|
422
|
+
|
423
|
+
static void
|
424
|
+
raise_event(VALUE trace_point, void *data)
|
425
|
+
{
|
426
|
+
VALUE expn_class, ancestors, pm_context;
|
427
|
+
int i;
|
428
|
+
debug_context_t *new_dc;
|
429
|
+
|
430
|
+
EVENT_SETUP;
|
431
|
+
|
432
|
+
raised_exception = rb_tracearg_raised_exception(trace_arg);
|
433
|
+
|
434
|
+
if (post_mortem == Qtrue && !rb_ivar_defined(raised_exception, rb_intern("@__bb_context")))
|
435
|
+
{
|
436
|
+
pm_context = context_dup(dc);
|
437
|
+
rb_ivar_set(raised_exception, rb_intern("@__bb_context"), pm_context);
|
438
|
+
|
439
|
+
Data_Get_Struct(pm_context, debug_context_t, new_dc);
|
440
|
+
rb_debug_inspector_open(context_backtrace_set, (void *)new_dc);
|
441
|
+
}
|
442
|
+
|
443
|
+
if (NIL_P(catchpoints) || dc->calced_stack_size == 0
|
444
|
+
|| RHASH_TBL(catchpoints)->num_entries == 0)
|
445
|
+
{
|
446
|
+
EVENT_TEARDOWN;
|
447
|
+
return;
|
448
|
+
}
|
449
|
+
|
450
|
+
expn_class = rb_obj_class(raised_exception);
|
451
|
+
ancestors = rb_mod_ancestors(expn_class);
|
452
|
+
for (i = 0; i < RARRAY_LENINT(ancestors); i++)
|
453
|
+
{
|
454
|
+
VALUE ancestor_class, module_name, hit_count;
|
455
|
+
|
456
|
+
ancestor_class = rb_ary_entry(ancestors, i);
|
457
|
+
module_name = rb_mod_name(ancestor_class);
|
458
|
+
hit_count = rb_hash_aref(catchpoints, module_name);
|
459
|
+
|
460
|
+
/* increment exception */
|
461
|
+
if (!NIL_P(hit_count))
|
462
|
+
{
|
463
|
+
rb_hash_aset(catchpoints, module_name, INT2FIX(FIX2INT(hit_count) + 1));
|
464
|
+
|
465
|
+
call_at_catchpoint(context, dc, raised_exception);
|
466
|
+
call_at_line(context, dc);
|
467
|
+
|
468
|
+
break;
|
469
|
+
}
|
470
|
+
}
|
471
|
+
|
472
|
+
EVENT_TEARDOWN;
|
473
|
+
}
|
474
|
+
|
475
|
+
|
476
|
+
/* Setup TracePoint functionality */
|
477
|
+
|
478
|
+
static void
|
479
|
+
register_tracepoints(VALUE self)
|
480
|
+
{
|
481
|
+
int i;
|
482
|
+
VALUE traces = tracepoints;
|
483
|
+
|
484
|
+
UNUSED(self);
|
485
|
+
|
486
|
+
if (NIL_P(traces))
|
487
|
+
{
|
488
|
+
int line_msk = RUBY_EVENT_LINE;
|
489
|
+
int call_msk = RUBY_EVENT_CALL;
|
490
|
+
int ret_msk = RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN;
|
491
|
+
int end_msk = RUBY_EVENT_END;
|
492
|
+
int raw_call_msk = RUBY_EVENT_C_CALL | RUBY_EVENT_B_CALL | RUBY_EVENT_CLASS;
|
493
|
+
int raw_ret_msk = RUBY_EVENT_C_RETURN;
|
494
|
+
int raise_msk = RUBY_EVENT_RAISE;
|
495
|
+
|
496
|
+
VALUE tpLine = rb_tracepoint_new(Qnil, line_msk, line_event, 0);
|
497
|
+
VALUE tpCall = rb_tracepoint_new(Qnil, call_msk, call_event, 0);
|
498
|
+
VALUE tpReturn = rb_tracepoint_new(Qnil, ret_msk, return_event, 0);
|
499
|
+
VALUE tpEnd = rb_tracepoint_new(Qnil, end_msk, end_event, 0);
|
500
|
+
VALUE tpCCall = rb_tracepoint_new(Qnil, raw_call_msk, raw_call_event, 0);
|
501
|
+
VALUE tpCReturn = rb_tracepoint_new(Qnil, raw_ret_msk, raw_return_event, 0);
|
502
|
+
VALUE tpRaise = rb_tracepoint_new(Qnil, raise_msk, raise_event, 0);
|
503
|
+
|
504
|
+
traces = rb_ary_new();
|
505
|
+
rb_ary_push(traces, tpLine);
|
506
|
+
rb_ary_push(traces, tpCall);
|
507
|
+
rb_ary_push(traces, tpReturn);
|
508
|
+
rb_ary_push(traces, tpEnd);
|
509
|
+
rb_ary_push(traces, tpCCall);
|
510
|
+
rb_ary_push(traces, tpCReturn);
|
511
|
+
rb_ary_push(traces, tpRaise);
|
512
|
+
|
513
|
+
tracepoints = traces;
|
514
|
+
}
|
515
|
+
|
516
|
+
for (i = 0; i < RARRAY_LENINT(traces); i++)
|
517
|
+
rb_tracepoint_enable(rb_ary_entry(traces, i));
|
518
|
+
}
|
519
|
+
|
520
|
+
static void
|
521
|
+
clear_tracepoints(VALUE self)
|
522
|
+
{
|
523
|
+
int i;
|
524
|
+
|
525
|
+
UNUSED(self);
|
526
|
+
|
527
|
+
for (i = RARRAY_LENINT(tracepoints) - 1; i >= 0; i--)
|
528
|
+
rb_tracepoint_disable(rb_ary_entry(tracepoints, i));
|
529
|
+
}
|
530
|
+
|
531
|
+
|
532
|
+
/* Byebug's Public API */
|
533
|
+
|
534
|
+
/*
|
535
|
+
* call-seq:
|
536
|
+
* Byebug.contexts -> array
|
537
|
+
*
|
538
|
+
* Returns an array of all contexts.
|
539
|
+
*/
|
540
|
+
static VALUE
|
541
|
+
Contexts(VALUE self)
|
542
|
+
{
|
543
|
+
volatile VALUE list;
|
544
|
+
volatile VALUE new_list;
|
545
|
+
VALUE context;
|
546
|
+
threads_table_t *t_tbl;
|
547
|
+
debug_context_t *dc;
|
548
|
+
int i;
|
549
|
+
|
550
|
+
UNUSED(self);
|
551
|
+
|
552
|
+
check_started();
|
553
|
+
|
554
|
+
new_list = rb_ary_new();
|
555
|
+
list = rb_funcall(rb_cThread, rb_intern("list"), 0);
|
556
|
+
|
557
|
+
for (i = 0; i < RARRAY_LENINT(list); i++)
|
558
|
+
{
|
559
|
+
VALUE thread = rb_ary_entry(list, i);
|
560
|
+
|
561
|
+
thread_context_lookup(thread, &context);
|
562
|
+
rb_ary_push(new_list, context);
|
563
|
+
}
|
564
|
+
|
565
|
+
Data_Get_Struct(threads, threads_table_t, t_tbl);
|
566
|
+
st_clear(t_tbl->tbl);
|
567
|
+
|
568
|
+
for (i = 0; i < RARRAY_LENINT(new_list); i++)
|
569
|
+
{
|
570
|
+
context = rb_ary_entry(new_list, i);
|
571
|
+
Data_Get_Struct(context, debug_context_t, dc);
|
572
|
+
st_insert(t_tbl->tbl, dc->thread, context);
|
573
|
+
}
|
574
|
+
|
575
|
+
return new_list;
|
576
|
+
}
|
577
|
+
|
578
|
+
/*
|
579
|
+
* call-seq:
|
580
|
+
* Byebug.thread_context(thread) -> context
|
581
|
+
*
|
582
|
+
* Returns context of the thread passed as an argument.
|
583
|
+
*/
|
584
|
+
static VALUE
|
585
|
+
Thread_context(VALUE self, VALUE thread)
|
586
|
+
{
|
587
|
+
VALUE context;
|
588
|
+
|
589
|
+
UNUSED(self);
|
590
|
+
|
591
|
+
check_started();
|
592
|
+
|
593
|
+
thread_context_lookup(thread, &context);
|
594
|
+
|
595
|
+
return context;
|
596
|
+
}
|
597
|
+
|
598
|
+
/*
|
599
|
+
* call-seq:
|
600
|
+
* Byebug.current_context -> context
|
601
|
+
*
|
602
|
+
* Returns the current context.
|
603
|
+
* <i>Note:</i> Byebug.current_context.thread == Thread.current
|
604
|
+
*/
|
605
|
+
static VALUE
|
606
|
+
Current_context(VALUE self)
|
607
|
+
{
|
608
|
+
VALUE context;
|
609
|
+
|
610
|
+
UNUSED(self);
|
611
|
+
|
612
|
+
thread_context_lookup(rb_thread_current(), &context);
|
613
|
+
|
614
|
+
return context;
|
615
|
+
}
|
616
|
+
|
617
|
+
/*
|
618
|
+
* call-seq:
|
619
|
+
* Byebug.started? -> bool
|
620
|
+
*
|
621
|
+
* Returns +true+ byebug is started.
|
622
|
+
*/
|
623
|
+
static VALUE
|
624
|
+
Started(VALUE self)
|
625
|
+
{
|
626
|
+
UNUSED(self);
|
627
|
+
|
628
|
+
return IS_STARTED ? Qtrue : Qfalse;
|
629
|
+
}
|
630
|
+
|
631
|
+
/*
|
632
|
+
* call-seq:
|
633
|
+
* Byebug.stop -> bool
|
634
|
+
*
|
635
|
+
* This method disables byebug. It returns +true+ if byebug was already
|
636
|
+
* disabled, otherwise it returns +false+.
|
637
|
+
*/
|
638
|
+
static VALUE
|
639
|
+
Stop(VALUE self)
|
640
|
+
{
|
641
|
+
UNUSED(self);
|
642
|
+
|
643
|
+
if (IS_STARTED)
|
644
|
+
{
|
645
|
+
clear_tracepoints(self);
|
646
|
+
|
647
|
+
breakpoints = Qnil;
|
648
|
+
catchpoints = Qnil;
|
649
|
+
|
650
|
+
return Qfalse;
|
651
|
+
}
|
652
|
+
|
653
|
+
return Qtrue;
|
654
|
+
}
|
655
|
+
|
656
|
+
static VALUE
|
657
|
+
Stoppable(VALUE self)
|
658
|
+
{
|
659
|
+
VALUE context;
|
660
|
+
debug_context_t *dc;
|
661
|
+
|
662
|
+
if (!IS_STARTED)
|
663
|
+
return Qfalse;
|
664
|
+
|
665
|
+
if (!NIL_P(breakpoints) && rb_funcall(breakpoints, idEmpty, 0) == Qfalse)
|
666
|
+
return Qfalse;
|
667
|
+
|
668
|
+
if (!NIL_P(catchpoints) && rb_funcall(catchpoints, idEmpty, 0) == Qfalse)
|
669
|
+
return Qfalse;
|
670
|
+
|
671
|
+
if (post_mortem == Qtrue)
|
672
|
+
return Qfalse;
|
673
|
+
|
674
|
+
if (RTEST(tracing))
|
675
|
+
return Qfalse;
|
676
|
+
|
677
|
+
context = Current_context(self);
|
678
|
+
if (!NIL_P(context))
|
679
|
+
{
|
680
|
+
Data_Get_Struct(context, debug_context_t, dc);
|
681
|
+
|
682
|
+
if (dc->steps > 0)
|
683
|
+
return Qfalse;
|
684
|
+
}
|
685
|
+
|
686
|
+
return Qtrue;
|
687
|
+
}
|
688
|
+
|
689
|
+
/*
|
690
|
+
* call-seq:
|
691
|
+
* Byebug.start -> bool
|
692
|
+
*
|
693
|
+
* The return value is the value of !Byebug.started? <i>before</i> issuing the
|
694
|
+
* +start+; That is, +true+ is returned, unless byebug was previously started.
|
695
|
+
*/
|
696
|
+
static VALUE
|
697
|
+
Start(VALUE self)
|
698
|
+
{
|
699
|
+
if (IS_STARTED)
|
700
|
+
return Qfalse;
|
701
|
+
|
702
|
+
catchpoints = rb_hash_new();
|
703
|
+
|
704
|
+
threads = create_threads_table();
|
705
|
+
|
706
|
+
register_tracepoints(self);
|
707
|
+
|
708
|
+
return Qtrue;
|
709
|
+
}
|
710
|
+
|
711
|
+
/*
|
712
|
+
* call-seq:
|
713
|
+
* Byebug.debug_load(file, stop = false) -> nil
|
714
|
+
*
|
715
|
+
* Same as Kernel#load but resets current context's frames.
|
716
|
+
* +stop+ parameter forces byebug to stop at the first line of code in +file+
|
717
|
+
*/
|
718
|
+
static VALUE
|
719
|
+
Debug_load(int argc, VALUE *argv, VALUE self)
|
720
|
+
{
|
721
|
+
VALUE file, stop, context;
|
722
|
+
debug_context_t *dc;
|
723
|
+
VALUE status = Qnil;
|
724
|
+
int state = 0;
|
725
|
+
|
726
|
+
UNUSED(self);
|
727
|
+
|
728
|
+
if (rb_scan_args(argc, argv, "11", &file, &stop) == 1)
|
729
|
+
stop = Qfalse;
|
730
|
+
|
731
|
+
Start(self);
|
732
|
+
|
733
|
+
context = Current_context(self);
|
734
|
+
Data_Get_Struct(context, debug_context_t, dc);
|
735
|
+
|
736
|
+
dc->calced_stack_size = 1;
|
737
|
+
|
738
|
+
if (RTEST(stop))
|
739
|
+
dc->steps = 1;
|
740
|
+
|
741
|
+
rb_load_protect(file, 0, &state);
|
742
|
+
if (0 != state)
|
743
|
+
{
|
744
|
+
status = rb_errinfo();
|
745
|
+
byebug_reset_stepping_stop_points(dc);
|
746
|
+
}
|
747
|
+
|
748
|
+
return status;
|
749
|
+
}
|
750
|
+
|
751
|
+
/*
|
752
|
+
* call-seq:
|
753
|
+
* Byebug.tracing? -> bool
|
754
|
+
*
|
755
|
+
* Returns +true+ if global tracing is enabled.
|
756
|
+
*/
|
757
|
+
static VALUE
|
758
|
+
Tracing(VALUE self)
|
759
|
+
{
|
760
|
+
UNUSED(self);
|
761
|
+
|
762
|
+
return tracing;
|
763
|
+
}
|
764
|
+
|
765
|
+
/*
|
766
|
+
* call-seq:
|
767
|
+
* Byebug.tracing = bool
|
768
|
+
*
|
769
|
+
* Sets the global tracing flag.
|
770
|
+
*/
|
771
|
+
static VALUE
|
772
|
+
Set_tracing(VALUE self, VALUE value)
|
773
|
+
{
|
774
|
+
UNUSED(self);
|
775
|
+
|
776
|
+
tracing = RTEST(value) ? Qtrue : Qfalse;
|
777
|
+
return value;
|
778
|
+
}
|
779
|
+
|
780
|
+
/*
|
781
|
+
* call-seq:
|
782
|
+
* Byebug.verbose? -> bool
|
783
|
+
*
|
784
|
+
* Returns +true+ if global verbose flag for TracePoint API events is enabled.
|
785
|
+
*/
|
786
|
+
static VALUE
|
787
|
+
Verbose(VALUE self)
|
788
|
+
{
|
789
|
+
UNUSED(self);
|
790
|
+
|
791
|
+
return verbose;
|
792
|
+
}
|
793
|
+
|
794
|
+
/*
|
795
|
+
* call-seq:
|
796
|
+
* Byebug.verbose = bool
|
797
|
+
*
|
798
|
+
* Sets the global verbose flag for TracePoint API events is enabled.
|
799
|
+
*/
|
800
|
+
static VALUE
|
801
|
+
Set_verbose(VALUE self, VALUE value)
|
802
|
+
{
|
803
|
+
UNUSED(self);
|
804
|
+
|
805
|
+
verbose = RTEST(value) ? Qtrue : Qfalse;
|
806
|
+
return value;
|
807
|
+
}
|
808
|
+
|
809
|
+
/*
|
810
|
+
* call-seq:
|
811
|
+
* Byebug.post_mortem? -> bool
|
812
|
+
*
|
813
|
+
* Returns +true+ if post-mortem debugging is enabled.
|
814
|
+
*/
|
815
|
+
static VALUE
|
816
|
+
Post_mortem(VALUE self)
|
817
|
+
{
|
818
|
+
UNUSED(self);
|
819
|
+
|
820
|
+
return post_mortem;
|
821
|
+
}
|
822
|
+
|
823
|
+
/*
|
824
|
+
* call-seq:
|
825
|
+
* Byebug.post_mortem = bool
|
826
|
+
*
|
827
|
+
* Sets post-moterm flag.
|
828
|
+
*/
|
829
|
+
static VALUE
|
830
|
+
Set_post_mortem(VALUE self, VALUE value)
|
831
|
+
{
|
832
|
+
UNUSED(self);
|
833
|
+
|
834
|
+
post_mortem = RTEST(value) ? Qtrue : Qfalse;
|
835
|
+
return value;
|
836
|
+
}
|
837
|
+
|
838
|
+
/*
|
839
|
+
* call-seq:
|
840
|
+
* Byebug.add_catchpoint(exception) -> exception
|
841
|
+
*
|
842
|
+
* Adds a new exception to the catchpoints hash.
|
843
|
+
*/
|
844
|
+
static VALUE
|
845
|
+
Add_catchpoint(VALUE self, VALUE value)
|
846
|
+
{
|
847
|
+
UNUSED(self);
|
848
|
+
|
849
|
+
if (TYPE(value) != T_STRING)
|
850
|
+
rb_raise(rb_eTypeError, "value of a catchpoint must be String");
|
851
|
+
|
852
|
+
rb_hash_aset(catchpoints, rb_str_dup(value), INT2FIX(0));
|
853
|
+
return value;
|
854
|
+
}
|
855
|
+
|
856
|
+
/*
|
857
|
+
* Document-module: Byebug
|
858
|
+
*
|
859
|
+
* == Summary
|
860
|
+
*
|
861
|
+
* This is a singleton class allows controlling byebug. Use it to start/stop
|
862
|
+
* byebug, set/remove breakpoints, etc.
|
863
|
+
*/
|
864
|
+
void
|
865
|
+
Init_byebug()
|
866
|
+
{
|
867
|
+
mByebug = rb_define_module("Byebug");
|
868
|
+
|
869
|
+
rb_define_module_function(mByebug, "add_catchpoint", Add_catchpoint, 1);
|
870
|
+
rb_define_module_function(mByebug, "breakpoints", Breakpoints, 0);
|
871
|
+
rb_define_module_function(mByebug, "catchpoints", Catchpoints, 0);
|
872
|
+
rb_define_module_function(mByebug, "contexts", Contexts, 0);
|
873
|
+
rb_define_module_function(mByebug, "current_context", Current_context, 0);
|
874
|
+
rb_define_module_function(mByebug, "debug_load", Debug_load, -1);
|
875
|
+
rb_define_module_function(mByebug, "post_mortem?", Post_mortem, 0);
|
876
|
+
rb_define_module_function(mByebug, "post_mortem=", Set_post_mortem, 1);
|
877
|
+
rb_define_module_function(mByebug, "raised_exception", Raised_exception, 0);
|
878
|
+
rb_define_module_function(mByebug, "start", Start, 0);
|
879
|
+
rb_define_module_function(mByebug, "started?", Started, 0);
|
880
|
+
rb_define_module_function(mByebug, "stop", Stop, 0);
|
881
|
+
rb_define_module_function(mByebug, "stoppable?", Stoppable, 0);
|
882
|
+
rb_define_module_function(mByebug, "thread_context", Thread_context, 1);
|
883
|
+
rb_define_module_function(mByebug, "tracing?", Tracing, 0);
|
884
|
+
rb_define_module_function(mByebug, "tracing=", Set_tracing, 1);
|
885
|
+
rb_define_module_function(mByebug, "verbose?", Verbose, 0);
|
886
|
+
rb_define_module_function(mByebug, "verbose=", Set_verbose, 1);
|
887
|
+
|
888
|
+
Init_threads_table(mByebug);
|
889
|
+
Init_byebug_context(mByebug);
|
890
|
+
Init_byebug_breakpoint(mByebug);
|
891
|
+
|
892
|
+
rb_global_variable(&breakpoints);
|
893
|
+
rb_global_variable(&catchpoints);
|
894
|
+
rb_global_variable(&tracepoints);
|
895
|
+
rb_global_variable(&raised_exception);
|
896
|
+
rb_global_variable(&threads);
|
897
|
+
|
898
|
+
idPuts = rb_intern("puts");
|
899
|
+
idEmpty = rb_intern("empty?");
|
900
|
+
}
|