byebug 11.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +897 -0
  3. data/CONTRIBUTING.md +58 -0
  4. data/GUIDE.md +1806 -0
  5. data/LICENSE +23 -0
  6. data/README.md +199 -0
  7. data/exe/byebug +6 -0
  8. data/ext/byebug/breakpoint.c +517 -0
  9. data/ext/byebug/byebug.c +905 -0
  10. data/ext/byebug/byebug.h +143 -0
  11. data/ext/byebug/context.c +673 -0
  12. data/ext/byebug/extconf.rb +12 -0
  13. data/ext/byebug/locker.c +96 -0
  14. data/ext/byebug/threads.c +230 -0
  15. data/lib/byebug.rb +3 -0
  16. data/lib/byebug/attacher.rb +48 -0
  17. data/lib/byebug/breakpoint.rb +111 -0
  18. data/lib/byebug/command.rb +111 -0
  19. data/lib/byebug/command_list.rb +34 -0
  20. data/lib/byebug/commands.rb +40 -0
  21. data/lib/byebug/commands/break.rb +112 -0
  22. data/lib/byebug/commands/catch.rb +78 -0
  23. data/lib/byebug/commands/condition.rb +55 -0
  24. data/lib/byebug/commands/continue.rb +68 -0
  25. data/lib/byebug/commands/debug.rb +38 -0
  26. data/lib/byebug/commands/delete.rb +55 -0
  27. data/lib/byebug/commands/disable.rb +33 -0
  28. data/lib/byebug/commands/disable/breakpoints.rb +42 -0
  29. data/lib/byebug/commands/disable/display.rb +43 -0
  30. data/lib/byebug/commands/display.rb +66 -0
  31. data/lib/byebug/commands/down.rb +45 -0
  32. data/lib/byebug/commands/edit.rb +69 -0
  33. data/lib/byebug/commands/enable.rb +33 -0
  34. data/lib/byebug/commands/enable/breakpoints.rb +42 -0
  35. data/lib/byebug/commands/enable/display.rb +43 -0
  36. data/lib/byebug/commands/finish.rb +57 -0
  37. data/lib/byebug/commands/frame.rb +57 -0
  38. data/lib/byebug/commands/help.rb +64 -0
  39. data/lib/byebug/commands/history.rb +39 -0
  40. data/lib/byebug/commands/info.rb +37 -0
  41. data/lib/byebug/commands/info/breakpoints.rb +65 -0
  42. data/lib/byebug/commands/info/display.rb +49 -0
  43. data/lib/byebug/commands/info/file.rb +80 -0
  44. data/lib/byebug/commands/info/line.rb +35 -0
  45. data/lib/byebug/commands/info/program.rb +49 -0
  46. data/lib/byebug/commands/interrupt.rb +34 -0
  47. data/lib/byebug/commands/irb.rb +50 -0
  48. data/lib/byebug/commands/kill.rb +45 -0
  49. data/lib/byebug/commands/list.rb +159 -0
  50. data/lib/byebug/commands/method.rb +53 -0
  51. data/lib/byebug/commands/next.rb +40 -0
  52. data/lib/byebug/commands/pry.rb +41 -0
  53. data/lib/byebug/commands/quit.rb +42 -0
  54. data/lib/byebug/commands/restart.rb +64 -0
  55. data/lib/byebug/commands/save.rb +72 -0
  56. data/lib/byebug/commands/set.rb +79 -0
  57. data/lib/byebug/commands/show.rb +45 -0
  58. data/lib/byebug/commands/skip.rb +85 -0
  59. data/lib/byebug/commands/source.rb +40 -0
  60. data/lib/byebug/commands/step.rb +40 -0
  61. data/lib/byebug/commands/thread.rb +34 -0
  62. data/lib/byebug/commands/thread/current.rb +37 -0
  63. data/lib/byebug/commands/thread/list.rb +43 -0
  64. data/lib/byebug/commands/thread/resume.rb +45 -0
  65. data/lib/byebug/commands/thread/stop.rb +43 -0
  66. data/lib/byebug/commands/thread/switch.rb +46 -0
  67. data/lib/byebug/commands/tracevar.rb +54 -0
  68. data/lib/byebug/commands/undisplay.rb +51 -0
  69. data/lib/byebug/commands/untracevar.rb +36 -0
  70. data/lib/byebug/commands/up.rb +45 -0
  71. data/lib/byebug/commands/var.rb +37 -0
  72. data/lib/byebug/commands/var/all.rb +41 -0
  73. data/lib/byebug/commands/var/args.rb +39 -0
  74. data/lib/byebug/commands/var/const.rb +49 -0
  75. data/lib/byebug/commands/var/global.rb +37 -0
  76. data/lib/byebug/commands/var/instance.rb +39 -0
  77. data/lib/byebug/commands/var/local.rb +39 -0
  78. data/lib/byebug/commands/where.rb +53 -0
  79. data/lib/byebug/context.rb +157 -0
  80. data/lib/byebug/core.rb +115 -0
  81. data/lib/byebug/errors.rb +29 -0
  82. data/lib/byebug/frame.rb +185 -0
  83. data/lib/byebug/helpers/bin.rb +47 -0
  84. data/lib/byebug/helpers/eval.rb +126 -0
  85. data/lib/byebug/helpers/file.rb +63 -0
  86. data/lib/byebug/helpers/frame.rb +75 -0
  87. data/lib/byebug/helpers/parse.rb +75 -0
  88. data/lib/byebug/helpers/path.rb +40 -0
  89. data/lib/byebug/helpers/reflection.rb +19 -0
  90. data/lib/byebug/helpers/string.rb +33 -0
  91. data/lib/byebug/helpers/thread.rb +67 -0
  92. data/lib/byebug/helpers/toggle.rb +62 -0
  93. data/lib/byebug/helpers/var.rb +54 -0
  94. data/lib/byebug/history.rb +130 -0
  95. data/lib/byebug/interface.rb +146 -0
  96. data/lib/byebug/interfaces/local_interface.rb +44 -0
  97. data/lib/byebug/interfaces/remote_interface.rb +50 -0
  98. data/lib/byebug/interfaces/script_interface.rb +33 -0
  99. data/lib/byebug/interfaces/test_interface.rb +67 -0
  100. data/lib/byebug/option_setter.rb +95 -0
  101. data/lib/byebug/printers/base.rb +68 -0
  102. data/lib/byebug/printers/plain.rb +44 -0
  103. data/lib/byebug/printers/texts/base.yml +115 -0
  104. data/lib/byebug/printers/texts/plain.yml +33 -0
  105. data/lib/byebug/processors/command_processor.rb +173 -0
  106. data/lib/byebug/processors/control_processor.rb +24 -0
  107. data/lib/byebug/processors/post_mortem_processor.rb +18 -0
  108. data/lib/byebug/processors/script_processor.rb +49 -0
  109. data/lib/byebug/remote.rb +85 -0
  110. data/lib/byebug/remote/client.rb +57 -0
  111. data/lib/byebug/remote/server.rb +47 -0
  112. data/lib/byebug/runner.rb +198 -0
  113. data/lib/byebug/setting.rb +79 -0
  114. data/lib/byebug/settings/autoirb.rb +29 -0
  115. data/lib/byebug/settings/autolist.rb +29 -0
  116. data/lib/byebug/settings/autopry.rb +29 -0
  117. data/lib/byebug/settings/autosave.rb +17 -0
  118. data/lib/byebug/settings/basename.rb +16 -0
  119. data/lib/byebug/settings/callstyle.rb +20 -0
  120. data/lib/byebug/settings/fullpath.rb +16 -0
  121. data/lib/byebug/settings/histfile.rb +20 -0
  122. data/lib/byebug/settings/histsize.rb +20 -0
  123. data/lib/byebug/settings/linetrace.rb +22 -0
  124. data/lib/byebug/settings/listsize.rb +21 -0
  125. data/lib/byebug/settings/post_mortem.rb +27 -0
  126. data/lib/byebug/settings/savefile.rb +20 -0
  127. data/lib/byebug/settings/stack_on_error.rb +15 -0
  128. data/lib/byebug/settings/width.rb +20 -0
  129. data/lib/byebug/source_file_formatter.rb +71 -0
  130. data/lib/byebug/subcommands.rb +54 -0
  131. data/lib/byebug/version.rb +8 -0
  132. metadata +199 -0
@@ -0,0 +1,143 @@
1
+ #ifndef BYEBUG
2
+ #define BYEBUG
3
+
4
+ #include <ruby.h>
5
+ #include <ruby/debug.h>
6
+
7
+ /* To prevent unused parameter warnings */
8
+ #define UNUSED(x) (void)(x)
9
+
10
+ /* flags */
11
+ #define CTX_FL_DEAD (1 << 1) /* this context belonged to a dead thread */
12
+ #define CTX_FL_IGNORE (1 << 2) /* this context belongs to ignored thread */
13
+ #define CTX_FL_SUSPEND (1 << 3) /* thread currently suspended */
14
+ #define CTX_FL_TRACING (1 << 4) /* call at_tracing method */
15
+ #define CTX_FL_WAS_RUNNING (1 << 5) /* thread was previously running */
16
+ #define CTX_FL_STOP_ON_RET (1 << 6) /* can stop on method 'end' */
17
+ #define CTX_FL_IGNORE_STEPS (1 << 7) /* doesn't countdown steps to break */
18
+
19
+ /* macro functions */
20
+ #define CTX_FL_TEST(c, f) ((c)->flags & (f))
21
+ #define CTX_FL_SET(c, f) \
22
+ do \
23
+ { \
24
+ (c)->flags |= (f); \
25
+ } while (0)
26
+ #define CTX_FL_UNSET(c, f) \
27
+ do \
28
+ { \
29
+ (c)->flags &= ~(f); \
30
+ } while (0)
31
+
32
+ /* types */
33
+ typedef enum {
34
+ CTX_STOP_NONE,
35
+ CTX_STOP_STEP,
36
+ CTX_STOP_BREAKPOINT,
37
+ CTX_STOP_CATCHPOINT
38
+ } ctx_stop_reason;
39
+
40
+ typedef struct
41
+ {
42
+ int calced_stack_size;
43
+ int flags;
44
+ ctx_stop_reason stop_reason;
45
+
46
+ VALUE thread;
47
+ int thnum;
48
+
49
+ int dest_frame; /* next stop's frame if stopped by next */
50
+ int lines; /* # of lines in dest_frame before stopping */
51
+ int steps; /* # of steps before stopping */
52
+ int steps_out; /* # of returns before stopping */
53
+
54
+ VALUE backtrace; /* [[loc, self, klass, binding], ...] */
55
+ } debug_context_t;
56
+
57
+ typedef enum {
58
+ LOCATION,
59
+ SELF,
60
+ CLASS,
61
+ BINDING
62
+ } frame_part;
63
+
64
+ struct call_with_inspection_data
65
+ {
66
+ debug_context_t *dc;
67
+ VALUE ctx;
68
+ ID id;
69
+ int argc;
70
+ VALUE *argv;
71
+ };
72
+
73
+ typedef struct
74
+ {
75
+ st_table *tbl;
76
+ } threads_table_t;
77
+
78
+ enum bp_type
79
+ {
80
+ BP_POS_TYPE,
81
+ BP_METHOD_TYPE
82
+ };
83
+
84
+ enum hit_condition
85
+ {
86
+ HIT_COND_NONE,
87
+ HIT_COND_GE,
88
+ HIT_COND_EQ,
89
+ HIT_COND_MOD
90
+ };
91
+
92
+ typedef struct
93
+ {
94
+ int id;
95
+ enum bp_type type;
96
+ VALUE source;
97
+ union
98
+ {
99
+ int line;
100
+ ID mid;
101
+ } pos;
102
+ VALUE expr;
103
+ VALUE enabled;
104
+ int hit_count;
105
+ int hit_value;
106
+ enum hit_condition hit_condition;
107
+ } breakpoint_t;
108
+
109
+ /* functions from locker.c */
110
+ extern void byebug_add_to_locked(VALUE thread);
111
+ extern VALUE byebug_pop_from_locked();
112
+ extern void byebug_remove_from_locked(VALUE thread);
113
+
114
+ /* functions from threads.c */
115
+ extern void Init_threads_table(VALUE mByebug);
116
+ extern VALUE create_threads_table(void);
117
+ extern void thread_context_lookup(VALUE thread, VALUE *context);
118
+ extern int is_living_thread(VALUE thread);
119
+ extern void acquire_lock(debug_context_t *dc);
120
+ extern void release_lock(void);
121
+
122
+ /* global variables */
123
+ extern VALUE threads;
124
+ extern VALUE next_thread;
125
+
126
+ /* functions from context.c */
127
+ extern void Init_byebug_context(VALUE mByebug);
128
+ extern VALUE byebug_context_create(VALUE thread);
129
+ extern VALUE context_dup(debug_context_t *context);
130
+ extern void byebug_reset_stepping_stop_points(debug_context_t *context);
131
+ extern VALUE call_with_debug_inspector(struct call_with_inspection_data *data);
132
+ extern VALUE context_backtrace_set(const rb_debug_inspector_t *inspector,
133
+ void *data);
134
+
135
+ /* functions from breakpoint.c */
136
+ extern void Init_byebug_breakpoint(VALUE mByebug);
137
+ extern VALUE find_breakpoint_by_pos(VALUE breakpoints, VALUE source, VALUE pos,
138
+ VALUE bind);
139
+
140
+ extern VALUE find_breakpoint_by_method(VALUE breakpoints, VALUE klass,
141
+ VALUE mid, VALUE bind, VALUE self);
142
+
143
+ #endif
@@ -0,0 +1,673 @@
1
+ #include "byebug.h"
2
+
3
+ static VALUE cContext;
4
+ static VALUE cDebugThread;
5
+ static int thnum_max = 0;
6
+
7
+ /* "Step", "Next" and "Finish" do their work by saving information about where
8
+ * to stop next. byebug_reset_stepping_stop_points removes/resets this information. */
9
+ extern void
10
+ byebug_reset_stepping_stop_points(debug_context_t *context)
11
+ {
12
+ context->dest_frame = -1;
13
+ context->lines = -1;
14
+ context->steps = -1;
15
+ context->steps_out = -1;
16
+ }
17
+
18
+ /*
19
+ * call-seq:
20
+ * context.dead? -> bool
21
+ *
22
+ * Returns +true+ if context doesn't represent a live context and is created
23
+ * during post-mortem exception handling.
24
+ */
25
+ static inline VALUE
26
+ Context_dead(VALUE self)
27
+ {
28
+ debug_context_t *context;
29
+
30
+ Data_Get_Struct(self, debug_context_t, context);
31
+ return CTX_FL_TEST(context, CTX_FL_DEAD) ? Qtrue : Qfalse;
32
+ }
33
+
34
+ static void
35
+ context_mark(void *data)
36
+ {
37
+ debug_context_t *context = (debug_context_t *)data;
38
+
39
+ rb_gc_mark(context->backtrace);
40
+ }
41
+
42
+ static VALUE
43
+ dc_backtrace(const debug_context_t *context)
44
+ {
45
+ return context->backtrace;
46
+ }
47
+
48
+ static int
49
+ dc_stack_size(debug_context_t *context)
50
+ {
51
+
52
+ if (NIL_P(dc_backtrace(context)))
53
+ return 0;
54
+
55
+ return RARRAY_LENINT(dc_backtrace(context));
56
+ }
57
+
58
+ extern VALUE
59
+ byebug_context_create(VALUE thread)
60
+ {
61
+ debug_context_t *context = ALLOC(debug_context_t);
62
+
63
+ context->flags = 0;
64
+ context->thnum = ++thnum_max;
65
+ context->thread = thread;
66
+ byebug_reset_stepping_stop_points(context);
67
+ context->stop_reason = CTX_STOP_NONE;
68
+
69
+ rb_debug_inspector_open(context_backtrace_set, (void *)context);
70
+ context->calced_stack_size = dc_stack_size(context) + 1;
71
+
72
+ if (rb_obj_class(thread) == cDebugThread)
73
+ CTX_FL_SET(context, CTX_FL_IGNORE);
74
+
75
+ return Data_Wrap_Struct(cContext, context_mark, 0, context);
76
+ }
77
+
78
+ extern VALUE
79
+ context_dup(debug_context_t *context)
80
+ {
81
+ debug_context_t *new_context = ALLOC(debug_context_t);
82
+
83
+ memcpy(new_context, context, sizeof(debug_context_t));
84
+ byebug_reset_stepping_stop_points(new_context);
85
+ new_context->backtrace = context->backtrace;
86
+ CTX_FL_SET(new_context, CTX_FL_DEAD);
87
+
88
+ return Data_Wrap_Struct(cContext, context_mark, 0, new_context);
89
+ }
90
+
91
+
92
+ static VALUE
93
+ dc_frame_get(const debug_context_t *context, int frame_index, frame_part type)
94
+ {
95
+ VALUE frame;
96
+
97
+ if (NIL_P(dc_backtrace(context)))
98
+ rb_raise(rb_eRuntimeError, "Backtrace information is not available");
99
+
100
+ if (frame_index >= RARRAY_LENINT(dc_backtrace(context)))
101
+ rb_raise(rb_eRuntimeError, "That frame doesn't exist!");
102
+
103
+ frame = rb_ary_entry(dc_backtrace(context), frame_index);
104
+ return rb_ary_entry(frame, type);
105
+ }
106
+
107
+ static VALUE
108
+ dc_frame_location(const debug_context_t *context, int frame_index)
109
+ {
110
+ return dc_frame_get(context, frame_index, LOCATION);
111
+ }
112
+
113
+ static VALUE
114
+ dc_frame_self(const debug_context_t *context, int frame_index)
115
+ {
116
+ return dc_frame_get(context, frame_index, SELF);
117
+ }
118
+
119
+ static VALUE
120
+ dc_frame_class(const debug_context_t *context, int frame_index)
121
+ {
122
+ return dc_frame_get(context, frame_index, CLASS);
123
+ }
124
+
125
+ static VALUE
126
+ dc_frame_binding(const debug_context_t *context, int frame_index)
127
+ {
128
+ return dc_frame_get(context, frame_index, BINDING);
129
+ }
130
+
131
+ static VALUE
132
+ load_backtrace(const rb_debug_inspector_t *inspector)
133
+ {
134
+ VALUE backtrace = rb_ary_new();
135
+ VALUE locs = rb_debug_inspector_backtrace_locations(inspector);
136
+ int i;
137
+
138
+ for (i = 0; i < RARRAY_LENINT(locs); i++)
139
+ {
140
+ VALUE frame = rb_ary_new();
141
+
142
+ rb_ary_push(frame, rb_ary_entry(locs, i));
143
+ rb_ary_push(frame, rb_debug_inspector_frame_self_get(inspector, i));
144
+ rb_ary_push(frame, rb_debug_inspector_frame_class_get(inspector, i));
145
+ rb_ary_push(frame, rb_debug_inspector_frame_binding_get(inspector, i));
146
+
147
+ rb_ary_push(backtrace, frame);
148
+ }
149
+
150
+ return backtrace;
151
+ }
152
+
153
+ extern VALUE
154
+ context_backtrace_set(const rb_debug_inspector_t *inspector, void *data)
155
+ {
156
+ debug_context_t *dc = (debug_context_t *)data;
157
+
158
+ dc->backtrace = load_backtrace(inspector);
159
+
160
+ return Qnil;
161
+ }
162
+
163
+ static VALUE
164
+ open_debug_inspector_i(const rb_debug_inspector_t *inspector, void *data)
165
+ {
166
+ struct call_with_inspection_data *cwi =
167
+ (struct call_with_inspection_data *)data;
168
+
169
+ cwi->dc->backtrace = load_backtrace(inspector);
170
+
171
+ return rb_funcall2(cwi->ctx, cwi->id, cwi->argc, cwi->argv);
172
+ }
173
+
174
+ static VALUE
175
+ open_debug_inspector(struct call_with_inspection_data *cwi)
176
+ {
177
+ return rb_debug_inspector_open(open_debug_inspector_i, cwi);
178
+ }
179
+
180
+ static VALUE
181
+ close_debug_inspector(struct call_with_inspection_data *cwi)
182
+ {
183
+ cwi->dc->backtrace = Qnil;
184
+ return Qnil;
185
+ }
186
+
187
+ extern VALUE
188
+ call_with_debug_inspector(struct call_with_inspection_data *data)
189
+ {
190
+ return rb_ensure(open_debug_inspector, (VALUE)data, close_debug_inspector,
191
+ (VALUE)data);
192
+ }
193
+
194
+ #define FRAME_SETUP \
195
+ debug_context_t *context; \
196
+ VALUE frame_no; \
197
+ int frame_n; \
198
+ Data_Get_Struct(self, debug_context_t, context); \
199
+ if (!rb_scan_args(argc, argv, "01", &frame_no)) \
200
+ frame_n = 0; \
201
+ else \
202
+ frame_n = FIX2INT(frame_no);
203
+
204
+ /*
205
+ * call-seq:
206
+ * context.frame_binding(frame_position = 0) -> binding
207
+ *
208
+ * Returns frame's binding.
209
+ */
210
+ static VALUE
211
+ Context_frame_binding(int argc, VALUE *argv, VALUE self)
212
+ {
213
+ FRAME_SETUP;
214
+
215
+ return dc_frame_binding(context, frame_n);
216
+ }
217
+
218
+ /*
219
+ * call-seq:
220
+ * context.frame_class(frame_position = 0) -> class
221
+ *
222
+ * Returns frame's defined class.
223
+ */
224
+ static VALUE
225
+ Context_frame_class(int argc, VALUE *argv, VALUE self)
226
+ {
227
+ FRAME_SETUP;
228
+
229
+ return dc_frame_class(context, frame_n);
230
+ }
231
+
232
+ /*
233
+ * call-seq:
234
+ * context.frame_file(frame_position = 0) -> string
235
+ *
236
+ * Returns the name of the file in the frame.
237
+ */
238
+ static VALUE
239
+ Context_frame_file(int argc, VALUE *argv, VALUE self)
240
+ {
241
+ VALUE loc, absolute_path;
242
+
243
+ FRAME_SETUP;
244
+
245
+ loc = dc_frame_location(context, frame_n);
246
+
247
+ absolute_path = rb_funcall(loc, rb_intern("absolute_path"), 0);
248
+
249
+ if (!NIL_P(absolute_path))
250
+ return absolute_path;
251
+
252
+ return rb_funcall(loc, rb_intern("path"), 0);
253
+ }
254
+
255
+ /*
256
+ * call-seq:
257
+ * context.frame_line(frame_position = 0) -> int
258
+ *
259
+ * Returns the line number in the file in the frame.
260
+ */
261
+ static VALUE
262
+ Context_frame_line(int argc, VALUE *argv, VALUE self)
263
+ {
264
+ VALUE loc;
265
+
266
+ FRAME_SETUP;
267
+
268
+ loc = dc_frame_location(context, frame_n);
269
+
270
+ return rb_funcall(loc, rb_intern("lineno"), 0);
271
+ }
272
+
273
+ /*
274
+ * call-seq:
275
+ * context.frame_method(frame_position = 0) -> sym
276
+ *
277
+ * Returns the sym of the method in the frame.
278
+ */
279
+ static VALUE
280
+ Context_frame_method(int argc, VALUE *argv, VALUE self)
281
+ {
282
+ VALUE loc;
283
+
284
+ FRAME_SETUP;
285
+
286
+ loc = dc_frame_location(context, frame_n);
287
+
288
+ return rb_str_intern(rb_funcall(loc, rb_intern("label"), 0));
289
+ }
290
+
291
+ /*
292
+ * call-seq:
293
+ * context.frame_self(frame_postion = 0) -> obj
294
+ *
295
+ * Returns self object of the frame.
296
+ */
297
+ static VALUE
298
+ Context_frame_self(int argc, VALUE *argv, VALUE self)
299
+ {
300
+ FRAME_SETUP;
301
+
302
+ return dc_frame_self(context, frame_n);
303
+ }
304
+
305
+ /*
306
+ * call-seq:
307
+ * context.ignored? -> bool
308
+ *
309
+ * Returns the ignore flag for the context, which marks whether the associated
310
+ * thread is ignored while debugging.
311
+ */
312
+ static inline VALUE
313
+ Context_ignored(VALUE self)
314
+ {
315
+ debug_context_t *context;
316
+
317
+ Data_Get_Struct(self, debug_context_t, context);
318
+ return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
319
+ }
320
+
321
+ /*
322
+ * call-seq:
323
+ * context.resume -> nil
324
+ *
325
+ * Resumes thread from the suspended mode.
326
+ */
327
+ static VALUE
328
+ Context_resume(VALUE self)
329
+ {
330
+ debug_context_t *context;
331
+
332
+ Data_Get_Struct(self, debug_context_t, context);
333
+
334
+ if (!CTX_FL_TEST(context, CTX_FL_SUSPEND))
335
+ return Qnil;
336
+
337
+ CTX_FL_UNSET(context, CTX_FL_SUSPEND);
338
+
339
+ if (CTX_FL_TEST(context, CTX_FL_WAS_RUNNING))
340
+ rb_thread_wakeup(context->thread);
341
+
342
+ return Qnil;
343
+ }
344
+
345
+ /*
346
+ * call-seq:
347
+ * context.backtrace-> Array
348
+ *
349
+ * Returns the frame stack of a context.
350
+ */
351
+ static inline VALUE
352
+ Context_backtrace(VALUE self)
353
+ {
354
+ debug_context_t *context;
355
+
356
+ Data_Get_Struct(self, debug_context_t, context);
357
+
358
+ return dc_backtrace(context);
359
+ }
360
+
361
+ static VALUE
362
+ Context_stop_reason(VALUE self)
363
+ {
364
+ debug_context_t *context;
365
+ const char *symbol;
366
+
367
+ Data_Get_Struct(self, debug_context_t, context);
368
+
369
+ if (CTX_FL_TEST(context, CTX_FL_DEAD))
370
+ symbol = "post-mortem";
371
+ else
372
+ switch (context->stop_reason)
373
+ {
374
+ case CTX_STOP_STEP:
375
+ symbol = "step";
376
+ break;
377
+ case CTX_STOP_BREAKPOINT:
378
+ symbol = "breakpoint";
379
+ break;
380
+ case CTX_STOP_CATCHPOINT:
381
+ symbol = "catchpoint";
382
+ break;
383
+ case CTX_STOP_NONE:
384
+ default:
385
+ symbol = "none";
386
+ }
387
+ return ID2SYM(rb_intern(symbol));
388
+ }
389
+
390
+ /*
391
+ * call-seq:
392
+ * context.step_into(steps, frame = 0)
393
+ *
394
+ * Stops the current context after a number of +steps+ are made from frame
395
+ * +frame+ (by default the newest one).
396
+ */
397
+ static VALUE
398
+ Context_step_into(int argc, VALUE *argv, VALUE self)
399
+ {
400
+ VALUE steps, v_frame;
401
+ int n_args, from_frame;
402
+ debug_context_t *context;
403
+
404
+ Data_Get_Struct(self, debug_context_t, context);
405
+
406
+ if (context->calced_stack_size == 0)
407
+ rb_raise(rb_eRuntimeError, "No frames collected.");
408
+
409
+ n_args = rb_scan_args(argc, argv, "11", &steps, &v_frame);
410
+
411
+ if (FIX2INT(steps) <= 0)
412
+ rb_raise(rb_eRuntimeError, "Steps argument must be positive.");
413
+
414
+ from_frame = n_args == 1 ? 0 : FIX2INT(v_frame);
415
+
416
+ if (from_frame < 0 || from_frame >= context->calced_stack_size)
417
+ rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
418
+ from_frame, context->calced_stack_size);
419
+ else if (from_frame > 0)
420
+ CTX_FL_SET(context, CTX_FL_IGNORE_STEPS);
421
+
422
+ context->steps = FIX2INT(steps);
423
+ context->dest_frame = context->calced_stack_size - from_frame;
424
+
425
+ return steps;
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * context.step_out(n_frames = 1, force = false)
431
+ *
432
+ * Stops after +n_frames+ frames are finished. +force+ parameter (if true)
433
+ * ensures that the execution will stop in the specified frame even when there
434
+ * are no more instructions to run. In that case, it will stop when the return
435
+ * event for that frame is triggered.
436
+ */
437
+ static VALUE
438
+ Context_step_out(int argc, VALUE *argv, VALUE self)
439
+ {
440
+ int n_args, n_frames;
441
+ VALUE v_frames, force;
442
+ debug_context_t *context;
443
+
444
+ n_args = rb_scan_args(argc, argv, "02", &v_frames, &force);
445
+ n_frames = n_args == 0 ? 1 : FIX2INT(v_frames);
446
+
447
+ Data_Get_Struct(self, debug_context_t, context);
448
+
449
+ if (n_frames < 0 || n_frames > context->calced_stack_size)
450
+ rb_raise(rb_eRuntimeError,
451
+ "You want to finish %d frames, but stack size is only %d",
452
+ n_frames, context->calced_stack_size);
453
+
454
+ context->steps_out = n_frames;
455
+ if (n_args == 2 && RTEST(force))
456
+ CTX_FL_SET(context, CTX_FL_STOP_ON_RET);
457
+ else
458
+ CTX_FL_UNSET(context, CTX_FL_STOP_ON_RET);
459
+
460
+ return Qnil;
461
+ }
462
+
463
+ /*
464
+ * call-seq:
465
+ * context.step_over(lines, frame = 0)
466
+ *
467
+ * Steps over +lines+ lines in frame +frame+ (by default the newest one) or
468
+ * higher (if frame +frame+ finishes).
469
+ */
470
+ static VALUE
471
+ Context_step_over(int argc, VALUE *argv, VALUE self)
472
+ {
473
+ int n_args, frame;
474
+ VALUE lines, v_frame;
475
+ debug_context_t *context;
476
+
477
+ Data_Get_Struct(self, debug_context_t, context);
478
+
479
+ if (context->calced_stack_size == 0)
480
+ rb_raise(rb_eRuntimeError, "No frames collected.");
481
+
482
+ n_args = rb_scan_args(argc, argv, "11", &lines, &v_frame);
483
+ frame = n_args == 1 ? 0 : FIX2INT(v_frame);
484
+
485
+ if (frame < 0 || frame >= context->calced_stack_size)
486
+ rb_raise(rb_eRuntimeError, "Destination frame (%d) is out of range (%d)",
487
+ frame, context->calced_stack_size);
488
+
489
+ context->lines = FIX2INT(lines);
490
+ context->dest_frame = context->calced_stack_size - frame;
491
+
492
+ return Qnil;
493
+ }
494
+
495
+ /*
496
+ * call-seq:
497
+ * context.suspend -> nil
498
+ *
499
+ * Suspends the thread when it is running.
500
+ */
501
+ static VALUE
502
+ Context_suspend(VALUE self)
503
+ {
504
+ VALUE status;
505
+ debug_context_t *context;
506
+
507
+ Data_Get_Struct(self, debug_context_t, context);
508
+
509
+ status = rb_funcall(context->thread, rb_intern("status"), 0);
510
+
511
+ if (rb_str_cmp(status, rb_str_new2("run")) == 0)
512
+ CTX_FL_SET(context, CTX_FL_WAS_RUNNING);
513
+ else if (rb_str_cmp(status, rb_str_new2("sleep")) == 0)
514
+ CTX_FL_UNSET(context, CTX_FL_WAS_RUNNING);
515
+ else
516
+ return Qnil;
517
+
518
+ CTX_FL_SET(context, CTX_FL_SUSPEND);
519
+
520
+ return Qnil;
521
+ }
522
+
523
+ /*
524
+ * call-seq:
525
+ * context.switch -> nil
526
+ *
527
+ * Switches execution to this context.
528
+ */
529
+ static VALUE
530
+ Context_switch(VALUE self)
531
+ {
532
+ debug_context_t *context;
533
+
534
+ Data_Get_Struct(self, debug_context_t, context);
535
+
536
+ next_thread = context->thread;
537
+
538
+ context->steps = 1;
539
+ context->steps_out = 0;
540
+ CTX_FL_SET(context, CTX_FL_STOP_ON_RET);
541
+
542
+ return Qnil;
543
+ }
544
+
545
+ /*
546
+ * call-seq:
547
+ * context.suspended? -> bool
548
+ *
549
+ * Returns +true+ if the thread is suspended by debugger.
550
+ */
551
+ static VALUE
552
+ Context_is_suspended(VALUE self)
553
+ {
554
+ debug_context_t *context;
555
+
556
+ Data_Get_Struct(self, debug_context_t, context);
557
+
558
+ return CTX_FL_TEST(context, CTX_FL_SUSPEND) ? Qtrue : Qfalse;
559
+ }
560
+
561
+ /*
562
+ * call-seq:
563
+ * context.thnum -> int
564
+ *
565
+ * Returns the context's number.
566
+ */
567
+ static inline VALUE
568
+ Context_thnum(VALUE self)
569
+ {
570
+ debug_context_t *context;
571
+
572
+ Data_Get_Struct(self, debug_context_t, context);
573
+ return INT2FIX(context->thnum);
574
+ }
575
+
576
+ /*
577
+ * call-seq:
578
+ * context.thread -> thread
579
+ *
580
+ * Returns the thread this context is associated with.
581
+ */
582
+ static inline VALUE
583
+ Context_thread(VALUE self)
584
+ {
585
+ debug_context_t *context;
586
+
587
+ Data_Get_Struct(self, debug_context_t, context);
588
+ return context->thread;
589
+ }
590
+
591
+ /*
592
+ * call-seq:
593
+ * context.tracing -> bool
594
+ *
595
+ * Returns the tracing flag for the current context.
596
+ */
597
+ static VALUE
598
+ Context_tracing(VALUE self)
599
+ {
600
+ debug_context_t *context;
601
+
602
+ Data_Get_Struct(self, debug_context_t, context);
603
+ return CTX_FL_TEST(context, CTX_FL_TRACING) ? Qtrue : Qfalse;
604
+ }
605
+
606
+ /*
607
+ * call-seq:
608
+ * context.tracing = bool
609
+ *
610
+ * Controls the tracing for this context.
611
+ */
612
+ static VALUE
613
+ Context_set_tracing(VALUE self, VALUE value)
614
+ {
615
+ debug_context_t *context;
616
+
617
+ Data_Get_Struct(self, debug_context_t, context);
618
+
619
+ if (RTEST(value))
620
+ CTX_FL_SET(context, CTX_FL_TRACING);
621
+ else
622
+ CTX_FL_UNSET(context, CTX_FL_TRACING);
623
+ return value;
624
+ }
625
+
626
+ /* :nodoc: */
627
+ static VALUE
628
+ dt_inherited(VALUE klass)
629
+ {
630
+ UNUSED(klass);
631
+
632
+ rb_raise(rb_eRuntimeError, "Can't inherit Byebug::DebugThread class");
633
+
634
+ return Qnil;
635
+ }
636
+
637
+ /*
638
+ * Document-class: Context
639
+ *
640
+ * == Summary
641
+ *
642
+ * Byebug keeps a single instance of this class per thread.
643
+ */
644
+ void
645
+ Init_byebug_context(VALUE mByebug)
646
+ {
647
+ cContext = rb_define_class_under(mByebug, "Context", rb_cObject);
648
+
649
+ rb_define_method(cContext, "backtrace", Context_backtrace, 0);
650
+ rb_define_method(cContext, "dead?", Context_dead, 0);
651
+ rb_define_method(cContext, "frame_binding", Context_frame_binding, -1);
652
+ rb_define_method(cContext, "frame_class", Context_frame_class, -1);
653
+ rb_define_method(cContext, "frame_file", Context_frame_file, -1);
654
+ rb_define_method(cContext, "frame_line", Context_frame_line, -1);
655
+ rb_define_method(cContext, "frame_method", Context_frame_method, -1);
656
+ rb_define_method(cContext, "frame_self", Context_frame_self, -1);
657
+ rb_define_method(cContext, "ignored?", Context_ignored, 0);
658
+ rb_define_method(cContext, "resume", Context_resume, 0);
659
+ rb_define_method(cContext, "step_into", Context_step_into, -1);
660
+ rb_define_method(cContext, "step_out", Context_step_out, -1);
661
+ rb_define_method(cContext, "step_over", Context_step_over, -1);
662
+ rb_define_method(cContext, "stop_reason", Context_stop_reason, 0);
663
+ rb_define_method(cContext, "suspend", Context_suspend, 0);
664
+ rb_define_method(cContext, "suspended?", Context_is_suspended, 0);
665
+ rb_define_method(cContext, "switch", Context_switch, 0);
666
+ rb_define_method(cContext, "thnum", Context_thnum, 0);
667
+ rb_define_method(cContext, "thread", Context_thread, 0);
668
+ rb_define_method(cContext, "tracing", Context_tracing, 0);
669
+ rb_define_method(cContext, "tracing=", Context_set_tracing, 1);
670
+
671
+ cDebugThread = rb_define_class_under(mByebug, "DebugThread", rb_cThread);
672
+ rb_define_singleton_method(cDebugThread, "inherited", dt_inherited, 1);
673
+ }