byebug 0.0.1
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.
- data/.gitignore +10 -0
- data/.travis.yml +8 -0
- data/AUTHORS +10 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +28 -0
- data/bin/byebug +395 -0
- data/byebug.gemspec +29 -0
- data/doc/hanoi.rb +35 -0
- data/doc/primes.rb +28 -0
- data/doc/rdebug-emacs.texi +1030 -0
- data/doc/test-tri2.rb +18 -0
- data/doc/tri3.rb +8 -0
- data/doc/triangle.rb +12 -0
- data/ext/byebug/breakpoint.c +476 -0
- data/ext/byebug/byebug.c +512 -0
- data/ext/byebug/byebug.h +131 -0
- data/ext/byebug/context.c +424 -0
- data/ext/byebug/extconf.rb +21 -0
- data/ext/byebug/locker.c +53 -0
- data/lib/byebug.rb +404 -0
- data/lib/byebug/command.rb +232 -0
- data/lib/byebug/commands/breakpoints.rb +153 -0
- data/lib/byebug/commands/catchpoint.rb +56 -0
- data/lib/byebug/commands/condition.rb +49 -0
- data/lib/byebug/commands/continue.rb +38 -0
- data/lib/byebug/commands/control.rb +110 -0
- data/lib/byebug/commands/display.rb +122 -0
- data/lib/byebug/commands/edit.rb +48 -0
- data/lib/byebug/commands/enable.rb +202 -0
- data/lib/byebug/commands/eval.rb +176 -0
- data/lib/byebug/commands/finish.rb +43 -0
- data/lib/byebug/commands/frame.rb +303 -0
- data/lib/byebug/commands/help.rb +56 -0
- data/lib/byebug/commands/info.rb +462 -0
- data/lib/byebug/commands/irb.rb +123 -0
- data/lib/byebug/commands/jump.rb +66 -0
- data/lib/byebug/commands/kill.rb +51 -0
- data/lib/byebug/commands/list.rb +94 -0
- data/lib/byebug/commands/method.rb +84 -0
- data/lib/byebug/commands/quit.rb +39 -0
- data/lib/byebug/commands/reload.rb +40 -0
- data/lib/byebug/commands/save.rb +90 -0
- data/lib/byebug/commands/set.rb +210 -0
- data/lib/byebug/commands/show.rb +246 -0
- data/lib/byebug/commands/skip.rb +35 -0
- data/lib/byebug/commands/source.rb +36 -0
- data/lib/byebug/commands/stepping.rb +83 -0
- data/lib/byebug/commands/threads.rb +189 -0
- data/lib/byebug/commands/tmate.rb +36 -0
- data/lib/byebug/commands/trace.rb +56 -0
- data/lib/byebug/commands/variables.rb +199 -0
- data/lib/byebug/context.rb +58 -0
- data/lib/byebug/helper.rb +69 -0
- data/lib/byebug/interface.rb +223 -0
- data/lib/byebug/processor.rb +468 -0
- data/lib/byebug/version.rb +3 -0
- data/man/rdebug.1 +241 -0
- data/test/breakpoints_test.rb +357 -0
- data/test/conditions_test.rb +77 -0
- data/test/continue_test.rb +44 -0
- data/test/display_test.rb +141 -0
- data/test/edit_test.rb +56 -0
- data/test/eval_test.rb +92 -0
- data/test/examples/breakpoint1.rb +15 -0
- data/test/examples/breakpoint2.rb +7 -0
- data/test/examples/conditions.rb +4 -0
- data/test/examples/continue.rb +4 -0
- data/test/examples/display.rb +5 -0
- data/test/examples/edit.rb +3 -0
- data/test/examples/edit2.rb +3 -0
- data/test/examples/eval.rb +4 -0
- data/test/examples/finish.rb +20 -0
- data/test/examples/frame.rb +20 -0
- data/test/examples/frame_threads.rb +31 -0
- data/test/examples/help.rb +2 -0
- data/test/examples/info.rb +38 -0
- data/test/examples/info2.rb +3 -0
- data/test/examples/info_threads.rb +48 -0
- data/test/examples/irb.rb +6 -0
- data/test/examples/jump.rb +14 -0
- data/test/examples/kill.rb +2 -0
- data/test/examples/list.rb +12 -0
- data/test/examples/method.rb +15 -0
- data/test/examples/post_mortem.rb +19 -0
- data/test/examples/quit.rb +2 -0
- data/test/examples/reload.rb +6 -0
- data/test/examples/restart.rb +6 -0
- data/test/examples/save.rb +3 -0
- data/test/examples/set.rb +3 -0
- data/test/examples/set_annotate.rb +12 -0
- data/test/examples/settings.rb +1 -0
- data/test/examples/show.rb +2 -0
- data/test/examples/source.rb +3 -0
- data/test/examples/stepping.rb +21 -0
- data/test/examples/thread.rb +32 -0
- data/test/examples/tmate.rb +10 -0
- data/test/examples/trace.rb +7 -0
- data/test/examples/trace_threads.rb +20 -0
- data/test/examples/variables.rb +26 -0
- data/test/finish_test.rb +48 -0
- data/test/frame_test.rb +143 -0
- data/test/help_test.rb +50 -0
- data/test/info_test.rb +313 -0
- data/test/irb_test.rb +81 -0
- data/test/jump_test.rb +70 -0
- data/test/kill_test.rb +48 -0
- data/test/list_test.rb +145 -0
- data/test/method_test.rb +70 -0
- data/test/post_mortem_test.rb +27 -0
- data/test/quit_test.rb +56 -0
- data/test/reload_test.rb +44 -0
- data/test/restart_test.rb +164 -0
- data/test/save_test.rb +92 -0
- data/test/set_test.rb +177 -0
- data/test/show_test.rb +293 -0
- data/test/source_test.rb +45 -0
- data/test/stepping_test.rb +130 -0
- data/test/support/breakpoint.rb +13 -0
- data/test/support/context.rb +14 -0
- data/test/support/matchers.rb +67 -0
- data/test/support/mocha_extensions.rb +72 -0
- data/test/support/processor.rb +7 -0
- data/test/support/test_dsl.rb +206 -0
- data/test/support/test_interface.rb +68 -0
- data/test/test_helper.rb +10 -0
- data/test/tmate_test.rb +44 -0
- data/test/trace_test.rb +159 -0
- data/test/variables_test.rb +119 -0
- metadata +265 -0
data/ext/byebug/byebug.c
ADDED
@@ -0,0 +1,512 @@
|
|
1
|
+
#include <byebug.h>
|
2
|
+
|
3
|
+
static VALUE mByebug; /* Ruby Byebug Module object */
|
4
|
+
static VALUE cContext;
|
5
|
+
static VALUE cDebugThread;
|
6
|
+
|
7
|
+
static VALUE debug = Qfalse;
|
8
|
+
static VALUE locker = Qnil;
|
9
|
+
static VALUE contexts;
|
10
|
+
static VALUE catchpoints;
|
11
|
+
static VALUE breakpoints;
|
12
|
+
|
13
|
+
static VALUE tpLine;
|
14
|
+
static VALUE tpCall;
|
15
|
+
static VALUE tpReturn;
|
16
|
+
static VALUE tpRaise;
|
17
|
+
|
18
|
+
static VALUE idAlive;
|
19
|
+
static VALUE idAtBreakpoint;
|
20
|
+
static VALUE idAtCatchpoint;
|
21
|
+
static VALUE idAtLine;
|
22
|
+
static VALUE idAtTracing;
|
23
|
+
|
24
|
+
static void
|
25
|
+
print_debug_info(char *event, VALUE path, VALUE lineno, VALUE method_id,
|
26
|
+
VALUE defined_class, int stack_size)
|
27
|
+
{
|
28
|
+
char *file;
|
29
|
+
const char *method_name, *class_name;
|
30
|
+
|
31
|
+
file = strrchr(RSTRING_PTR(path), '/');
|
32
|
+
method_name = rb_id2name(SYM2ID(method_id));
|
33
|
+
class_name = NIL_P(defined_class) ? "undef" : rb_class2name(defined_class);
|
34
|
+
fprintf(stderr, "%s: file=%s, line=%d, class=%s, method=%s, stack=%d\n",
|
35
|
+
event, ++file, FIX2INT(lineno), class_name, method_name, stack_size);
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE
|
40
|
+
Byebug_thread_context(VALUE self, VALUE thread)
|
41
|
+
{
|
42
|
+
VALUE context;
|
43
|
+
|
44
|
+
context = rb_hash_aref(contexts, thread);
|
45
|
+
if (context == Qnil) {
|
46
|
+
context = context_create(thread, cDebugThread);
|
47
|
+
rb_hash_aset(contexts, thread, context);
|
48
|
+
}
|
49
|
+
return context;
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE
|
53
|
+
Byebug_current_context(VALUE self)
|
54
|
+
{
|
55
|
+
return Byebug_thread_context(self, rb_thread_current());
|
56
|
+
}
|
57
|
+
|
58
|
+
static int
|
59
|
+
remove_dead_threads(VALUE thread, VALUE context, VALUE ignored)
|
60
|
+
{
|
61
|
+
return (IS_THREAD_ALIVE(thread)) ? ST_CONTINUE : ST_DELETE;
|
62
|
+
}
|
63
|
+
|
64
|
+
static void
|
65
|
+
cleanup(debug_context_t *context)
|
66
|
+
{
|
67
|
+
VALUE thread;
|
68
|
+
|
69
|
+
context->stop_reason = CTX_STOP_NONE;
|
70
|
+
|
71
|
+
/* release a lock */
|
72
|
+
locker = Qnil;
|
73
|
+
|
74
|
+
/* let the next thread run */
|
75
|
+
thread = remove_from_locked();
|
76
|
+
if(thread != Qnil)
|
77
|
+
rb_thread_run(thread);
|
78
|
+
}
|
79
|
+
|
80
|
+
static int
|
81
|
+
check_start_processing(debug_context_t *context, VALUE thread)
|
82
|
+
{
|
83
|
+
/* return if thread is marked as 'ignored'.
|
84
|
+
byebug's threads are marked this way
|
85
|
+
*/
|
86
|
+
if(CTX_FL_TEST(context, CTX_FL_IGNORE)) return 0;
|
87
|
+
|
88
|
+
while(1)
|
89
|
+
{
|
90
|
+
/* halt execution of the current thread if the byebug
|
91
|
+
is activated in another
|
92
|
+
*/
|
93
|
+
while(locker != Qnil && locker != thread)
|
94
|
+
{
|
95
|
+
add_to_locked(thread);
|
96
|
+
rb_thread_stop();
|
97
|
+
}
|
98
|
+
|
99
|
+
/* stop the current thread if it's marked as suspended */
|
100
|
+
if(CTX_FL_TEST(context, CTX_FL_SUSPEND) && locker != thread)
|
101
|
+
{
|
102
|
+
CTX_FL_SET(context, CTX_FL_WAS_RUNNING);
|
103
|
+
rb_thread_stop();
|
104
|
+
}
|
105
|
+
else break;
|
106
|
+
}
|
107
|
+
|
108
|
+
/* return if the current thread is the locker */
|
109
|
+
if(locker != Qnil) return 0;
|
110
|
+
|
111
|
+
/* only the current thread can proceed */
|
112
|
+
locker = thread;
|
113
|
+
|
114
|
+
/* ignore a skipped section of code */
|
115
|
+
if(CTX_FL_TEST(context, CTX_FL_SKIPPED)) {
|
116
|
+
cleanup(context);
|
117
|
+
return 0;
|
118
|
+
}
|
119
|
+
return 1;
|
120
|
+
}
|
121
|
+
|
122
|
+
static inline void
|
123
|
+
load_frame_info(VALUE trace_point, VALUE *path, VALUE *lineno, VALUE *method_id,
|
124
|
+
VALUE *defined_class, VALUE *binding,
|
125
|
+
VALUE *self)
|
126
|
+
{
|
127
|
+
rb_trace_point_t *tp;
|
128
|
+
|
129
|
+
tp = rb_tracearg_from_tracepoint(trace_point);
|
130
|
+
|
131
|
+
*path = rb_tracearg_path(tp);
|
132
|
+
*lineno = rb_tracearg_lineno(tp);
|
133
|
+
*binding = rb_tracearg_binding(tp);
|
134
|
+
*self = rb_tracearg_self(tp);
|
135
|
+
*method_id = rb_tracearg_method_id(tp);
|
136
|
+
*defined_class = rb_tracearg_defined_class(tp);
|
137
|
+
}
|
138
|
+
|
139
|
+
static void
|
140
|
+
call_at_line(debug_context_t *context, char *file, int line,
|
141
|
+
VALUE context_object, VALUE path, VALUE lineno)
|
142
|
+
{
|
143
|
+
CTX_FL_UNSET(context, CTX_FL_STEPPED);
|
144
|
+
CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
|
145
|
+
context->last_file = file;
|
146
|
+
context->last_line = line;
|
147
|
+
rb_funcall(context_object, idAtLine, 2, path, lineno);
|
148
|
+
}
|
149
|
+
|
150
|
+
static void
|
151
|
+
process_line_event(VALUE trace_point, void *data)
|
152
|
+
{
|
153
|
+
VALUE path, lineno, method_id, defined_class, binding, self;
|
154
|
+
VALUE context_object;
|
155
|
+
VALUE breakpoint;
|
156
|
+
debug_context_t *context;
|
157
|
+
int moved;
|
158
|
+
|
159
|
+
context_object = Byebug_current_context(mByebug);
|
160
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
161
|
+
if (!check_start_processing(context, rb_thread_current())) return;
|
162
|
+
|
163
|
+
load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class,
|
164
|
+
&binding, &self);
|
165
|
+
if (debug == Qtrue)
|
166
|
+
print_debug_info("line", path, lineno, method_id, defined_class,
|
167
|
+
context->stack_size);
|
168
|
+
|
169
|
+
update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
|
170
|
+
defined_class, binding, self);
|
171
|
+
|
172
|
+
moved = context->last_line != FIX2INT(lineno) || context->last_file == NULL ||
|
173
|
+
strcmp(context->last_file, RSTRING_PTR(path)) != 0;
|
174
|
+
|
175
|
+
if (CTX_FL_TEST(context, CTX_FL_TRACING))
|
176
|
+
rb_funcall(context_object, idAtTracing, 2, path, lineno);
|
177
|
+
|
178
|
+
if (context->dest_frame == -1 || context->stack_size == context->dest_frame)
|
179
|
+
{
|
180
|
+
if (moved || !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE))
|
181
|
+
context->stop_next--;
|
182
|
+
if (context->stop_next < 0)
|
183
|
+
context->stop_next = -1;
|
184
|
+
if (moved || (CTX_FL_TEST(context, CTX_FL_STEPPED) && !CTX_FL_TEST(context, CTX_FL_FORCE_MOVE)))
|
185
|
+
{
|
186
|
+
context->stop_line--;
|
187
|
+
CTX_FL_UNSET(context, CTX_FL_STEPPED);
|
188
|
+
}
|
189
|
+
}
|
190
|
+
else if (context->stack_size < context->dest_frame)
|
191
|
+
{
|
192
|
+
context->stop_next = 0;
|
193
|
+
}
|
194
|
+
|
195
|
+
breakpoint = find_breakpoint_by_pos(breakpoints, path, lineno, binding);
|
196
|
+
if (context->stop_next == 0 || context->stop_line == 0 ||
|
197
|
+
breakpoint != Qnil)
|
198
|
+
{
|
199
|
+
context->stop_reason = CTX_STOP_STEP;
|
200
|
+
if (breakpoint != Qnil) {
|
201
|
+
rb_funcall(context_object, idAtBreakpoint, 1, breakpoint);
|
202
|
+
}
|
203
|
+
reset_stepping_stop_points(context);
|
204
|
+
call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
|
205
|
+
path, lineno);
|
206
|
+
}
|
207
|
+
cleanup(context);
|
208
|
+
}
|
209
|
+
|
210
|
+
static void
|
211
|
+
process_return_event(VALUE trace_point, void *data)
|
212
|
+
{
|
213
|
+
VALUE path, lineno, method_id, defined_class, binding, self;
|
214
|
+
VALUE context_object;
|
215
|
+
debug_context_t *context;
|
216
|
+
|
217
|
+
context_object = Byebug_current_context(mByebug);
|
218
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
219
|
+
if (!check_start_processing(context, rb_thread_current())) return;
|
220
|
+
|
221
|
+
if(context->stack_size == context->stop_frame)
|
222
|
+
{
|
223
|
+
context->stop_next = 1;
|
224
|
+
context->stop_frame = 0;
|
225
|
+
}
|
226
|
+
|
227
|
+
load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class,
|
228
|
+
&binding, &self);
|
229
|
+
if (debug == Qtrue)
|
230
|
+
print_debug_info("return", path, lineno, method_id, defined_class,
|
231
|
+
context->stack_size);
|
232
|
+
|
233
|
+
// rb_funcall(context_object, idAtReturn, 2, path, lineno);
|
234
|
+
|
235
|
+
pop_frame(context_object);
|
236
|
+
cleanup(context);
|
237
|
+
}
|
238
|
+
|
239
|
+
static void
|
240
|
+
process_call_event(VALUE trace_point, void *data)
|
241
|
+
{
|
242
|
+
VALUE path, lineno, method_id, defined_class, binding, self;
|
243
|
+
VALUE context_object;
|
244
|
+
VALUE breakpoint;
|
245
|
+
debug_context_t *context;
|
246
|
+
|
247
|
+
context_object = Byebug_current_context(mByebug);
|
248
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
249
|
+
if (!check_start_processing(context, rb_thread_current())) return;
|
250
|
+
|
251
|
+
load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class,
|
252
|
+
&binding, &self);
|
253
|
+
if (debug == Qtrue)
|
254
|
+
print_debug_info("call", path, lineno, method_id, defined_class,
|
255
|
+
context->stack_size);
|
256
|
+
|
257
|
+
push_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
|
258
|
+
defined_class, binding, self);
|
259
|
+
|
260
|
+
breakpoint = find_breakpoint_by_method(breakpoints, defined_class,
|
261
|
+
SYM2ID(method_id),
|
262
|
+
binding, self);
|
263
|
+
if (breakpoint != Qnil) {
|
264
|
+
context->stop_reason = CTX_STOP_BREAKPOINT;
|
265
|
+
rb_funcall(context_object, idAtBreakpoint, 1, breakpoint);
|
266
|
+
call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
|
267
|
+
path, lineno);
|
268
|
+
}
|
269
|
+
|
270
|
+
cleanup(context);
|
271
|
+
}
|
272
|
+
|
273
|
+
static void
|
274
|
+
process_raise_event(VALUE trace_point, void *data)
|
275
|
+
{
|
276
|
+
VALUE path, lineno, method_id, defined_class, binding, self;
|
277
|
+
VALUE context_object;
|
278
|
+
VALUE hit_count;
|
279
|
+
VALUE exception_name;
|
280
|
+
debug_context_t *context;
|
281
|
+
int c_hit_count;
|
282
|
+
|
283
|
+
context_object = Byebug_current_context(mByebug);
|
284
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
285
|
+
if (!check_start_processing(context, rb_thread_current())) return;
|
286
|
+
|
287
|
+
load_frame_info(trace_point, &path, &lineno, &method_id, &defined_class,
|
288
|
+
&binding, &self);
|
289
|
+
update_frame(context_object, RSTRING_PTR(path), FIX2INT(lineno), method_id,
|
290
|
+
defined_class, binding, self);
|
291
|
+
|
292
|
+
if (catchpoint_hit_count(catchpoints, rb_errinfo(), &exception_name) != Qnil) {
|
293
|
+
/* On 64-bit systems with gcc and -O2 there seems to be
|
294
|
+
an optimization bug in running INT2FIX(FIX2INT...)..)
|
295
|
+
So we do this in two steps.
|
296
|
+
*/
|
297
|
+
c_hit_count = FIX2INT(rb_hash_aref(catchpoints, exception_name)) + 1;
|
298
|
+
hit_count = INT2FIX(c_hit_count);
|
299
|
+
rb_hash_aset(catchpoints, exception_name, hit_count);
|
300
|
+
context->stop_reason = CTX_STOP_CATCHPOINT;
|
301
|
+
rb_funcall(context_object, idAtCatchpoint, 1, rb_errinfo());
|
302
|
+
call_at_line(context, RSTRING_PTR(path), FIX2INT(lineno), context_object,
|
303
|
+
path, lineno);
|
304
|
+
}
|
305
|
+
|
306
|
+
cleanup(context);
|
307
|
+
}
|
308
|
+
|
309
|
+
|
310
|
+
static VALUE
|
311
|
+
Byebug_setup_tracepoints(VALUE self)
|
312
|
+
{
|
313
|
+
if (catchpoints != Qnil) return Qnil;
|
314
|
+
contexts = rb_hash_new();
|
315
|
+
breakpoints = rb_ary_new();
|
316
|
+
catchpoints = rb_hash_new();
|
317
|
+
|
318
|
+
tpLine = rb_tracepoint_new(Qnil,
|
319
|
+
RUBY_EVENT_LINE,
|
320
|
+
process_line_event, NULL);
|
321
|
+
rb_tracepoint_enable(tpLine);
|
322
|
+
|
323
|
+
tpReturn = rb_tracepoint_new(Qnil,
|
324
|
+
RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN | RUBY_EVENT_CLASS | RUBY_EVENT_END,
|
325
|
+
process_return_event, NULL);
|
326
|
+
rb_tracepoint_enable(tpReturn);
|
327
|
+
|
328
|
+
tpCall = rb_tracepoint_new(Qnil,
|
329
|
+
RUBY_EVENT_CALL | RUBY_EVENT_C_CALL | RUBY_EVENT_B_CALL,
|
330
|
+
process_call_event, NULL);
|
331
|
+
rb_tracepoint_enable(tpCall);
|
332
|
+
|
333
|
+
tpRaise = rb_tracepoint_new(Qnil,
|
334
|
+
RUBY_EVENT_RAISE, process_raise_event, NULL);
|
335
|
+
rb_tracepoint_enable(tpRaise);
|
336
|
+
|
337
|
+
return Qnil;
|
338
|
+
}
|
339
|
+
|
340
|
+
static VALUE
|
341
|
+
Byebug_remove_tracepoints(VALUE self)
|
342
|
+
{
|
343
|
+
contexts = Qnil;
|
344
|
+
breakpoints = Qnil;
|
345
|
+
catchpoints = Qnil;
|
346
|
+
|
347
|
+
if (tpLine != Qnil) rb_tracepoint_disable(tpLine);
|
348
|
+
tpLine = Qnil;
|
349
|
+
if (tpReturn != Qnil) rb_tracepoint_disable(tpReturn);
|
350
|
+
tpReturn = Qnil;
|
351
|
+
if (tpCall != Qnil) rb_tracepoint_disable(tpCall);
|
352
|
+
tpCall = Qnil;
|
353
|
+
if (tpRaise != Qnil) rb_tracepoint_disable(tpRaise);
|
354
|
+
tpRaise = Qnil;
|
355
|
+
return Qnil;
|
356
|
+
}
|
357
|
+
|
358
|
+
static int
|
359
|
+
values_i(VALUE key, VALUE value, VALUE ary)
|
360
|
+
{
|
361
|
+
rb_ary_push(ary, value);
|
362
|
+
return ST_CONTINUE;
|
363
|
+
}
|
364
|
+
|
365
|
+
static VALUE
|
366
|
+
Byebug_started(VALUE self)
|
367
|
+
{
|
368
|
+
return catchpoints != Qnil ? Qtrue : Qfalse;
|
369
|
+
}
|
370
|
+
|
371
|
+
static VALUE
|
372
|
+
Byebug_stop(VALUE self)
|
373
|
+
{
|
374
|
+
if (Byebug_started(self))
|
375
|
+
{
|
376
|
+
Byebug_remove_tracepoints(self);
|
377
|
+
return Qfalse;
|
378
|
+
}
|
379
|
+
return Qtrue;
|
380
|
+
}
|
381
|
+
|
382
|
+
static VALUE
|
383
|
+
Byebug_start(VALUE self)
|
384
|
+
{
|
385
|
+
VALUE result;
|
386
|
+
|
387
|
+
if (Byebug_started(self))
|
388
|
+
result = Qfalse;
|
389
|
+
else
|
390
|
+
{
|
391
|
+
Byebug_setup_tracepoints(self);
|
392
|
+
result = Qtrue;
|
393
|
+
}
|
394
|
+
|
395
|
+
if (rb_block_given_p())
|
396
|
+
rb_ensure(rb_yield, self, Byebug_stop, self);
|
397
|
+
|
398
|
+
return result;
|
399
|
+
}
|
400
|
+
|
401
|
+
static VALUE
|
402
|
+
Byebug_load(int argc, VALUE *argv, VALUE self)
|
403
|
+
{
|
404
|
+
VALUE file, stop, context_object;
|
405
|
+
debug_context_t *context;
|
406
|
+
int state = 0;
|
407
|
+
|
408
|
+
if (rb_scan_args(argc, argv, "11", &file, &stop) == 1)
|
409
|
+
{
|
410
|
+
stop = Qfalse;
|
411
|
+
}
|
412
|
+
|
413
|
+
Byebug_start(self);
|
414
|
+
|
415
|
+
context_object = Byebug_current_context(self);
|
416
|
+
Data_Get_Struct(context_object, debug_context_t, context);
|
417
|
+
context->stack_size = 0;
|
418
|
+
if (RTEST(stop)) context->stop_next = 1;
|
419
|
+
|
420
|
+
/* Initializing $0 to the script's path */
|
421
|
+
ruby_script(RSTRING_PTR(file));
|
422
|
+
rb_load_protect(file, 0, &state);
|
423
|
+
if (0 != state)
|
424
|
+
{
|
425
|
+
VALUE errinfo = rb_errinfo();
|
426
|
+
//debug_suspend(self);
|
427
|
+
reset_stepping_stop_points(context);
|
428
|
+
rb_set_errinfo(Qnil);
|
429
|
+
return errinfo;
|
430
|
+
}
|
431
|
+
|
432
|
+
/* We should run all at_exit handler's in order to provide,
|
433
|
+
* for instance, a chance to run all defined test cases */
|
434
|
+
rb_exec_end_proc();
|
435
|
+
|
436
|
+
return Qnil;
|
437
|
+
}
|
438
|
+
|
439
|
+
|
440
|
+
|
441
|
+
static VALUE
|
442
|
+
Byebug_contexts(VALUE self)
|
443
|
+
{
|
444
|
+
VALUE ary;
|
445
|
+
|
446
|
+
ary = rb_ary_new();
|
447
|
+
|
448
|
+
/* check that all contexts point to alive threads */
|
449
|
+
rb_hash_foreach(contexts, remove_dead_threads, 0);
|
450
|
+
|
451
|
+
rb_hash_foreach(contexts, values_i, ary);
|
452
|
+
|
453
|
+
return ary;
|
454
|
+
}
|
455
|
+
|
456
|
+
static VALUE
|
457
|
+
Byebug_breakpoints(VALUE self)
|
458
|
+
{
|
459
|
+
return breakpoints;
|
460
|
+
}
|
461
|
+
|
462
|
+
static VALUE
|
463
|
+
Byebug_catchpoints(VALUE self)
|
464
|
+
{
|
465
|
+
if (catchpoints == Qnil)
|
466
|
+
rb_raise(rb_eRuntimeError, "Byebug.start is not called yet.");
|
467
|
+
return catchpoints;
|
468
|
+
}
|
469
|
+
|
470
|
+
/*
|
471
|
+
* Document-class: Byebug
|
472
|
+
*
|
473
|
+
* == Summary
|
474
|
+
*
|
475
|
+
* This is a singleton class allows controlling the byebug. Use it to start/stop
|
476
|
+
* byebug, set/remove breakpoints, etc.
|
477
|
+
*/
|
478
|
+
void
|
479
|
+
Init_byebug()
|
480
|
+
{
|
481
|
+
mByebug = rb_define_module("Byebug");
|
482
|
+
rb_define_module_function(mByebug, "setup_tracepoints", Byebug_setup_tracepoints, 0);
|
483
|
+
rb_define_module_function(mByebug, "remove_tracepoints", Byebug_remove_tracepoints, 0);
|
484
|
+
rb_define_module_function(mByebug, "current_context", Byebug_current_context, 0);
|
485
|
+
rb_define_module_function(mByebug, "contexts", Byebug_contexts, 0);
|
486
|
+
rb_define_module_function(mByebug, "breakpoints", Byebug_breakpoints, 0);
|
487
|
+
rb_define_module_function(mByebug, "catchpoints", Byebug_catchpoints, 0);
|
488
|
+
rb_define_module_function(mByebug, "_start", Byebug_start, 0);
|
489
|
+
rb_define_module_function(mByebug, "stop", Byebug_stop, 0);
|
490
|
+
rb_define_module_function(mByebug, "started?", Byebug_started, 0);
|
491
|
+
rb_define_module_function(mByebug, "debug_load", Byebug_load, -1);
|
492
|
+
|
493
|
+
idAlive = rb_intern("alive?");
|
494
|
+
idAtBreakpoint = rb_intern("at_breakpoint");
|
495
|
+
idAtCatchpoint = rb_intern("at_catchpoint");
|
496
|
+
idAtTracing = rb_intern("at_tracing");
|
497
|
+
idAtLine = rb_intern("at_line");
|
498
|
+
|
499
|
+
cContext = Init_context(mByebug);
|
500
|
+
|
501
|
+
Init_breakpoint(mByebug);
|
502
|
+
|
503
|
+
cDebugThread = rb_define_class_under(mByebug, "DebugThread", rb_cThread);
|
504
|
+
contexts = Qnil;
|
505
|
+
catchpoints = Qnil;
|
506
|
+
breakpoints = Qnil;
|
507
|
+
|
508
|
+
rb_global_variable(&locker);
|
509
|
+
rb_global_variable(&breakpoints);
|
510
|
+
rb_global_variable(&catchpoints);
|
511
|
+
rb_global_variable(&contexts);
|
512
|
+
}
|