byebug 3.5.1 → 4.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/.gitignore +4 -1
- data/.rubocop.yml +18 -1
- data/.travis.yml +21 -1
- data/CHANGELOG.md +356 -308
- data/CONTRIBUTING.md +31 -15
- data/GUIDE.md +859 -475
- data/Gemfile +8 -10
- data/LICENSE +1 -1
- data/README.md +41 -45
- data/Rakefile +30 -28
- data/byebug.gemspec +18 -18
- data/ext/byebug/breakpoint.c +88 -75
- data/ext/byebug/byebug.c +253 -252
- data/ext/byebug/byebug.h +53 -53
- data/ext/byebug/context.c +188 -159
- data/ext/byebug/extconf.rb +9 -6
- data/ext/byebug/locker.c +53 -11
- data/ext/byebug/threads.c +137 -39
- data/lib/byebug/attacher.rb +7 -2
- data/lib/byebug/breakpoint.rb +30 -0
- data/lib/byebug/command.rb +36 -32
- data/lib/byebug/commands/break.rb +49 -48
- data/lib/byebug/commands/catch.rb +64 -0
- data/lib/byebug/commands/condition.rb +13 -9
- data/lib/byebug/commands/continue.rb +8 -4
- data/lib/byebug/commands/delete.rb +10 -4
- data/lib/byebug/commands/display.rb +33 -25
- data/lib/byebug/commands/edit.rb +18 -13
- data/lib/byebug/commands/enable_disable.rb +26 -24
- data/lib/byebug/commands/eval.rb +77 -35
- data/lib/byebug/commands/finish.rb +9 -5
- data/lib/byebug/commands/frame.rb +66 -125
- data/lib/byebug/commands/help.rb +14 -21
- data/lib/byebug/commands/history.rb +5 -1
- data/lib/byebug/commands/info.rb +41 -106
- data/lib/byebug/commands/interrupt.rb +6 -2
- data/lib/byebug/commands/irb.rb +5 -2
- data/lib/byebug/commands/kill.rb +6 -2
- data/lib/byebug/commands/list.rb +21 -14
- data/lib/byebug/commands/method.rb +17 -9
- data/lib/byebug/commands/pry.rb +13 -3
- data/lib/byebug/commands/quit.rb +10 -5
- data/lib/byebug/commands/restart.rb +12 -19
- data/lib/byebug/commands/save.rb +10 -6
- data/lib/byebug/commands/set.rb +15 -14
- data/lib/byebug/commands/show.rb +8 -8
- data/lib/byebug/commands/source.rb +14 -8
- data/lib/byebug/commands/stepping.rb +15 -29
- data/lib/byebug/commands/threads.rb +73 -49
- data/lib/byebug/commands/tracevar.rb +56 -0
- data/lib/byebug/commands/undisplay.rb +8 -4
- data/lib/byebug/commands/untracevar.rb +38 -0
- data/lib/byebug/commands/var.rb +107 -0
- data/lib/byebug/context.rb +78 -42
- data/lib/byebug/core.rb +78 -40
- data/lib/byebug/helper.rb +58 -42
- data/lib/byebug/history.rb +12 -1
- data/lib/byebug/interface.rb +91 -11
- data/lib/byebug/interfaces/local_interface.rb +12 -19
- data/lib/byebug/interfaces/remote_interface.rb +12 -15
- data/lib/byebug/interfaces/script_interface.rb +14 -18
- data/lib/byebug/interfaces/test_interface.rb +54 -0
- data/lib/byebug/printers/base.rb +64 -0
- data/lib/byebug/printers/plain.rb +53 -0
- data/lib/byebug/processor.rb +20 -1
- data/lib/byebug/processors/command_processor.rb +57 -172
- data/lib/byebug/processors/control_command_processor.rb +16 -43
- data/lib/byebug/remote.rb +13 -7
- data/lib/byebug/runner.rb +102 -54
- data/lib/byebug/setting.rb +45 -68
- data/lib/byebug/settings/autoeval.rb +2 -0
- data/lib/byebug/settings/autoirb.rb +3 -0
- data/lib/byebug/settings/autolist.rb +3 -0
- data/lib/byebug/settings/autosave.rb +2 -0
- data/lib/byebug/settings/basename.rb +2 -0
- data/lib/byebug/settings/callstyle.rb +2 -0
- data/lib/byebug/settings/fullpath.rb +2 -0
- data/lib/byebug/settings/histfile.rb +2 -0
- data/lib/byebug/settings/histsize.rb +2 -0
- data/lib/byebug/settings/linetrace.rb +2 -0
- data/lib/byebug/settings/listsize.rb +2 -0
- data/lib/byebug/settings/post_mortem.rb +7 -2
- data/lib/byebug/settings/stack_on_error.rb +2 -0
- data/lib/byebug/settings/verbose.rb +2 -0
- data/lib/byebug/settings/width.rb +2 -0
- data/lib/byebug/state.rb +12 -0
- data/lib/byebug/states/control_state.rb +26 -0
- data/lib/byebug/states/regular_state.rb +178 -0
- data/lib/byebug/version.rb +1 -1
- metadata +24 -109
- data/lib/byebug/commands/catchpoint.rb +0 -53
- data/lib/byebug/commands/reload.rb +0 -29
- data/lib/byebug/commands/trace.rb +0 -50
- data/lib/byebug/commands/variables.rb +0 -206
- data/lib/byebug/options.rb +0 -46
- data/lib/byebug/settings/autoreload.rb +0 -12
- data/lib/byebug/settings/forcestep.rb +0 -14
- data/lib/byebug/settings/testing.rb +0 -12
- data/lib/byebug/settings/tracing_plus.rb +0 -11
- data/test/commands/break_test.rb +0 -364
- data/test/commands/condition_test.rb +0 -85
- data/test/commands/continue_test.rb +0 -47
- data/test/commands/delete_test.rb +0 -26
- data/test/commands/display_test.rb +0 -37
- data/test/commands/edit_test.rb +0 -52
- data/test/commands/eval_test.rb +0 -89
- data/test/commands/finish_test.rb +0 -74
- data/test/commands/frame_test.rb +0 -223
- data/test/commands/help_test.rb +0 -66
- data/test/commands/history_test.rb +0 -61
- data/test/commands/info_test.rb +0 -238
- data/test/commands/interrupt_test.rb +0 -45
- data/test/commands/irb_test.rb +0 -28
- data/test/commands/kill_test.rb +0 -50
- data/test/commands/list_test.rb +0 -174
- data/test/commands/method_test.rb +0 -52
- data/test/commands/post_mortem_test.rb +0 -71
- data/test/commands/pry_test.rb +0 -26
- data/test/commands/quit_test.rb +0 -53
- data/test/commands/reload_test.rb +0 -39
- data/test/commands/restart_test.rb +0 -46
- data/test/commands/save_test.rb +0 -67
- data/test/commands/set_test.rb +0 -140
- data/test/commands/show_test.rb +0 -76
- data/test/commands/source_test.rb +0 -46
- data/test/commands/stepping_test.rb +0 -192
- data/test/commands/thread_test.rb +0 -164
- data/test/commands/trace_test.rb +0 -71
- data/test/commands/undisplay_test.rb +0 -75
- data/test/commands/variables_test.rb +0 -105
- data/test/debugger_alias_test.rb +0 -7
- data/test/runner_test.rb +0 -150
- data/test/support/matchers.rb +0 -65
- data/test/support/test_interface.rb +0 -59
- data/test/support/utils.rb +0 -122
- data/test/test_helper.rb +0 -58
data/ext/byebug/extconf.rb
CHANGED
@@ -5,13 +5,16 @@ end
|
|
5
5
|
|
6
6
|
require 'mkmf'
|
7
7
|
|
8
|
-
RbConfig::MAKEFILE_CONFIG
|
8
|
+
makefile_config = RbConfig::MAKEFILE_CONFIG
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
makefile_config['CC'] = ENV['CC'] if ENV['CC']
|
11
|
+
|
12
|
+
makefile_config['CFLAGS'] << ' -Wall -Werror'
|
13
|
+
makefile_config['CFLAGS'] << ' -gdwarf-2 -g3 -O0' if ENV['debug']
|
14
|
+
|
15
|
+
if makefile_config['CC'] =~ /clang/
|
16
|
+
makefile_config['CFLAGS'] << ' -Wno-unknown-warning-option'
|
14
17
|
end
|
15
18
|
|
16
19
|
dir_config('ruby')
|
17
|
-
create_makefile('byebug/byebug')
|
20
|
+
with_cflags(makefile_config['CFLAGS']) { create_makefile('byebug/byebug') }
|
data/ext/byebug/locker.c
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
#include <byebug.h>
|
2
2
|
|
3
|
-
|
3
|
+
/**
|
4
|
+
* A simple linked list containing locked threads, FIFO style.
|
5
|
+
*/
|
6
|
+
|
7
|
+
typedef struct locked_thread_t
|
8
|
+
{
|
4
9
|
VALUE thread;
|
5
10
|
struct locked_thread_t *next;
|
6
11
|
} locked_thread_t;
|
@@ -13,12 +18,13 @@ is_in_locked(VALUE thread)
|
|
13
18
|
{
|
14
19
|
locked_thread_t *node;
|
15
20
|
|
16
|
-
if (!locked_head)
|
21
|
+
if (!locked_head)
|
22
|
+
return 0;
|
17
23
|
|
18
24
|
for (node = locked_head; node != locked_tail; node = node->next)
|
19
|
-
|
20
|
-
|
21
|
-
|
25
|
+
if (node->thread == thread)
|
26
|
+
return 1;
|
27
|
+
|
22
28
|
return 0;
|
23
29
|
}
|
24
30
|
|
@@ -27,28 +33,64 @@ add_to_locked(VALUE thread)
|
|
27
33
|
{
|
28
34
|
locked_thread_t *node;
|
29
35
|
|
30
|
-
if (is_in_locked(thread))
|
36
|
+
if (is_in_locked(thread))
|
37
|
+
return;
|
31
38
|
|
32
39
|
node = ALLOC(locked_thread_t);
|
33
40
|
node->thread = thread;
|
34
41
|
node->next = NULL;
|
35
|
-
|
42
|
+
|
43
|
+
if (locked_tail)
|
44
|
+
locked_tail->next = node;
|
45
|
+
|
36
46
|
locked_tail = node;
|
37
|
-
|
47
|
+
|
48
|
+
if (!locked_head)
|
49
|
+
locked_head = node;
|
38
50
|
}
|
39
51
|
|
40
52
|
extern VALUE
|
41
|
-
|
53
|
+
pop_from_locked()
|
42
54
|
{
|
43
55
|
VALUE thread;
|
44
56
|
locked_thread_t *node;
|
45
57
|
|
46
|
-
if (locked_head
|
58
|
+
if (!locked_head)
|
59
|
+
return Qnil;
|
47
60
|
|
48
61
|
node = locked_head;
|
49
62
|
locked_head = locked_head->next;
|
50
|
-
|
63
|
+
|
64
|
+
if (locked_tail == node)
|
65
|
+
locked_tail = NULL;
|
66
|
+
|
51
67
|
thread = node->thread;
|
52
68
|
xfree(node);
|
69
|
+
|
53
70
|
return thread;
|
54
71
|
}
|
72
|
+
|
73
|
+
extern void
|
74
|
+
remove_from_locked(VALUE thread)
|
75
|
+
{
|
76
|
+
locked_thread_t *node;
|
77
|
+
locked_thread_t *next_node;
|
78
|
+
|
79
|
+
if (NIL_P(thread) || !locked_head || !is_in_locked(thread))
|
80
|
+
return;
|
81
|
+
|
82
|
+
if (locked_head->thread == thread)
|
83
|
+
{
|
84
|
+
pop_from_locked();
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
for (node = locked_head; node != locked_tail; node = node->next)
|
89
|
+
if (node->next && node->next->thread == thread)
|
90
|
+
{
|
91
|
+
next_node = node->next;
|
92
|
+
node->next = next_node->next;
|
93
|
+
xfree(next_node);
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
}
|
data/ext/byebug/threads.c
CHANGED
@@ -3,31 +3,41 @@
|
|
3
3
|
/* Threads table class */
|
4
4
|
static VALUE cThreadsTable;
|
5
5
|
|
6
|
+
/* If not Qnil, holds the next thread that must be run */
|
7
|
+
VALUE next_thread = Qnil;
|
8
|
+
|
9
|
+
/* To allow thread syncronization, we must stop threads when debugging */
|
10
|
+
VALUE locker = Qnil;
|
11
|
+
|
6
12
|
static int
|
7
13
|
t_tbl_mark_keyvalue(st_data_t key, st_data_t value, st_data_t tbl)
|
8
14
|
{
|
9
|
-
|
15
|
+
UNUSED(tbl);
|
10
16
|
|
11
|
-
|
17
|
+
rb_gc_mark((VALUE) key);
|
12
18
|
|
13
|
-
|
14
|
-
|
19
|
+
if (!value)
|
20
|
+
return ST_CONTINUE;
|
21
|
+
|
22
|
+
rb_gc_mark((VALUE) value);
|
15
23
|
|
16
24
|
return ST_CONTINUE;
|
17
25
|
}
|
18
26
|
|
19
27
|
static void
|
20
|
-
t_tbl_mark(void*
|
28
|
+
t_tbl_mark(void *data)
|
21
29
|
{
|
22
|
-
threads_table_t *t_tbl = (threads_table_t *)data;
|
30
|
+
threads_table_t *t_tbl = (threads_table_t *) data;
|
23
31
|
st_table *tbl = t_tbl->tbl;
|
24
|
-
|
32
|
+
|
33
|
+
st_foreach(tbl, t_tbl_mark_keyvalue, (st_data_t) tbl);
|
25
34
|
}
|
26
35
|
|
27
36
|
static void
|
28
|
-
t_tbl_free(void*
|
37
|
+
t_tbl_free(void *data)
|
29
38
|
{
|
30
|
-
threads_table_t *t_tbl = (threads_table_t*)data;
|
39
|
+
threads_table_t *t_tbl = (threads_table_t *) data;
|
40
|
+
|
31
41
|
st_free_table(t_tbl->tbl);
|
32
42
|
xfree(t_tbl);
|
33
43
|
}
|
@@ -46,16 +56,6 @@ create_threads_table(void)
|
|
46
56
|
return Data_Wrap_Struct(cThreadsTable, t_tbl_mark, t_tbl_free, t_tbl);
|
47
57
|
}
|
48
58
|
|
49
|
-
/*
|
50
|
-
* The condition to be in the thread's table is to be either running or
|
51
|
-
* sleeping, namely, to be Thread#alive?
|
52
|
-
*/
|
53
|
-
static int
|
54
|
-
is_living_thread(VALUE thread)
|
55
|
-
{
|
56
|
-
return rb_funcall(thread, rb_intern("alive?"), 0) == Qtrue;
|
57
|
-
}
|
58
|
-
|
59
59
|
/*
|
60
60
|
* Checks a single entry in the threads table.
|
61
61
|
*
|
@@ -63,20 +63,42 @@ is_living_thread(VALUE thread)
|
|
63
63
|
* thread, the entry is removed from the thread's list.
|
64
64
|
*/
|
65
65
|
static int
|
66
|
-
check_thread_i(st_data_t key, st_data_t value, st_data_t
|
66
|
+
check_thread_i(st_data_t key, st_data_t value, st_data_t data)
|
67
67
|
{
|
68
|
-
|
68
|
+
UNUSED(data);
|
69
69
|
|
70
|
-
if (!
|
70
|
+
if (!value)
|
71
|
+
return ST_DELETE;
|
72
|
+
|
73
|
+
if (!is_living_thread((VALUE) key))
|
74
|
+
return ST_DELETE;
|
71
75
|
|
72
76
|
return ST_CONTINUE;
|
73
77
|
}
|
74
78
|
|
79
|
+
/*
|
80
|
+
* Checks whether a thread is either in the running or sleeping state.
|
81
|
+
*/
|
82
|
+
int
|
83
|
+
is_living_thread(VALUE thread)
|
84
|
+
{
|
85
|
+
VALUE status = rb_funcall(thread, rb_intern("status"), 0);
|
86
|
+
|
87
|
+
if (NIL_P(status) || status == Qfalse)
|
88
|
+
return 0;
|
89
|
+
|
90
|
+
if (rb_str_cmp(status, rb_str_new2("run")) == 0
|
91
|
+
|| rb_str_cmp(status, rb_str_new2("sleep")) == 0)
|
92
|
+
return 1;
|
93
|
+
|
94
|
+
return 0;
|
95
|
+
}
|
96
|
+
|
75
97
|
/*
|
76
98
|
* Checks threads table for dead/finished threads.
|
77
99
|
*/
|
78
100
|
void
|
79
|
-
|
101
|
+
cleanup_dead_threads(void)
|
80
102
|
{
|
81
103
|
threads_table_t *t_tbl;
|
82
104
|
|
@@ -84,12 +106,16 @@ check_threads_table(void)
|
|
84
106
|
st_foreach(t_tbl->tbl, check_thread_i, 0);
|
85
107
|
}
|
86
108
|
|
109
|
+
/*
|
110
|
+
* Looks up a context in the threads table. If not present, it creates it.
|
111
|
+
*/
|
87
112
|
void
|
88
|
-
thread_context_lookup(VALUE thread, VALUE *context)
|
113
|
+
thread_context_lookup(VALUE thread, VALUE * context)
|
89
114
|
{
|
90
115
|
threads_table_t *t_tbl;
|
91
116
|
|
92
117
|
Data_Get_Struct(threads, threads_table_t, t_tbl);
|
118
|
+
|
93
119
|
if (!st_lookup(t_tbl->tbl, thread, context) || !*context)
|
94
120
|
{
|
95
121
|
*context = context_create(thread);
|
@@ -97,26 +123,95 @@ thread_context_lookup(VALUE thread, VALUE *context)
|
|
97
123
|
}
|
98
124
|
}
|
99
125
|
|
126
|
+
/*
|
127
|
+
* Holds thread execution while another thread is active.
|
128
|
+
*
|
129
|
+
* Thanks to this, all threads are "frozen" while the user is typing commands.
|
130
|
+
*/
|
100
131
|
void
|
101
|
-
|
132
|
+
acquire_lock(debug_context_t * dc)
|
102
133
|
{
|
103
|
-
while (
|
134
|
+
while ((!NIL_P(locker) && locker != rb_thread_current())
|
135
|
+
|| CTX_FL_TEST(dc, CTX_FL_SUSPEND))
|
104
136
|
{
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
rb_thread_stop();
|
110
|
-
}
|
111
|
-
|
112
|
-
/* stop the current thread if it's marked as suspended */
|
113
|
-
if (CTX_FL_TEST(dc, CTX_FL_SUSPEND) && locker != rb_thread_current())
|
114
|
-
{
|
137
|
+
add_to_locked(rb_thread_current());
|
138
|
+
rb_thread_stop();
|
139
|
+
|
140
|
+
if (CTX_FL_TEST(dc, CTX_FL_SUSPEND))
|
115
141
|
CTX_FL_SET(dc, CTX_FL_WAS_RUNNING);
|
116
|
-
rb_thread_stop();
|
117
|
-
}
|
118
|
-
else break;
|
119
142
|
}
|
143
|
+
|
144
|
+
locker = rb_thread_current();
|
145
|
+
}
|
146
|
+
|
147
|
+
/*
|
148
|
+
* Releases our global lock and passes execution on to another thread, either
|
149
|
+
* the thread specified by +next_thread+ or any other thread if +next_thread+
|
150
|
+
* is nil.
|
151
|
+
*/
|
152
|
+
void
|
153
|
+
release_lock(void)
|
154
|
+
{
|
155
|
+
VALUE thread;
|
156
|
+
|
157
|
+
cleanup_dead_threads();
|
158
|
+
|
159
|
+
locker = Qnil;
|
160
|
+
|
161
|
+
if (NIL_P(next_thread))
|
162
|
+
thread = pop_from_locked();
|
163
|
+
else
|
164
|
+
{
|
165
|
+
remove_from_locked(next_thread);
|
166
|
+
thread = next_thread;
|
167
|
+
}
|
168
|
+
|
169
|
+
if (thread == next_thread)
|
170
|
+
next_thread = Qnil;
|
171
|
+
|
172
|
+
if (!NIL_P(thread) && is_living_thread(thread))
|
173
|
+
rb_thread_run(thread);
|
174
|
+
}
|
175
|
+
|
176
|
+
/*
|
177
|
+
* call-seq:
|
178
|
+
* Byebug.unlock -> nil
|
179
|
+
*
|
180
|
+
* Unlocks global switch so other threads can run.
|
181
|
+
*/
|
182
|
+
static VALUE
|
183
|
+
Unlock(VALUE self)
|
184
|
+
{
|
185
|
+
UNUSED(self);
|
186
|
+
|
187
|
+
release_lock();
|
188
|
+
|
189
|
+
return locker;
|
190
|
+
}
|
191
|
+
|
192
|
+
/*
|
193
|
+
* call-seq:
|
194
|
+
* Byebug.lock -> Thread.current
|
195
|
+
*
|
196
|
+
* Locks global switch to reserve execution to current thread exclusively.
|
197
|
+
*/
|
198
|
+
static VALUE
|
199
|
+
Lock(VALUE self)
|
200
|
+
{
|
201
|
+
debug_context_t *dc;
|
202
|
+
VALUE context;
|
203
|
+
|
204
|
+
UNUSED(self);
|
205
|
+
|
206
|
+
if (!is_living_thread(rb_thread_current()))
|
207
|
+
rb_raise(rb_eRuntimeError, "Current thread is dead!");
|
208
|
+
|
209
|
+
thread_context_lookup(rb_thread_current(), &context);
|
210
|
+
Data_Get_Struct(context, debug_context_t, dc);
|
211
|
+
|
212
|
+
acquire_lock(dc);
|
213
|
+
|
214
|
+
return locker;
|
120
215
|
}
|
121
216
|
|
122
217
|
/*
|
@@ -131,4 +226,7 @@ void
|
|
131
226
|
Init_threads_table(VALUE mByebug)
|
132
227
|
{
|
133
228
|
cThreadsTable = rb_define_class_under(mByebug, "ThreadsTable", rb_cObject);
|
229
|
+
|
230
|
+
rb_define_module_function(mByebug, "unlock", Unlock, 0);
|
231
|
+
rb_define_module_function(mByebug, "lock", Lock, 0);
|
134
232
|
}
|
data/lib/byebug/attacher.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
+
#
|
2
|
+
# Main Container for all of Byebug's code
|
3
|
+
#
|
1
4
|
module Byebug
|
2
5
|
#
|
3
6
|
# Enters byebug right before (or right after if _before_ is false) return
|
4
7
|
# events occur. Before entering byebug the init script is read.
|
5
8
|
#
|
6
9
|
def self.attach(steps_out, before)
|
10
|
+
setup_cmd_line_args
|
11
|
+
|
7
12
|
start
|
8
|
-
|
9
|
-
|
13
|
+
run_init_script
|
14
|
+
|
10
15
|
current_context.step_out(steps_out, before)
|
11
16
|
end
|
12
17
|
end
|
data/lib/byebug/breakpoint.rb
CHANGED
@@ -39,6 +39,36 @@ module Byebug
|
|
39
39
|
Byebug.breakpoints.reject! { |b| b.id == id }
|
40
40
|
end
|
41
41
|
|
42
|
+
#
|
43
|
+
# Returns an array of line numbers in file named +filename+ where
|
44
|
+
# breakpoints could be set. The list will contain an entry for each
|
45
|
+
# distinct line event call so it is possible (and possibly useful) for a
|
46
|
+
# line number appear more than once.
|
47
|
+
#
|
48
|
+
# @param filename [String] File name to inspect for possible breakpoints
|
49
|
+
#
|
50
|
+
def self.potential_lines(filename)
|
51
|
+
name, lines = "#{Time.new.to_i}_#{rand(2**31)}", {}
|
52
|
+
iseq = RubyVM::InstructionSequence.compile(File.read(filename), name)
|
53
|
+
|
54
|
+
iseq.disasm.each_line do |line|
|
55
|
+
res = /^\d+ (?<insn>\w+)\s+.+\(\s*(?<lineno>\d+)\)$/.match(line)
|
56
|
+
next unless res && res[:insn] == 'trace'
|
57
|
+
|
58
|
+
lines[res[:lineno].to_i] = true
|
59
|
+
end
|
60
|
+
|
61
|
+
lines.keys
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Returns true if a breakpoint could be set in line number +lineno+ in file
|
66
|
+
# name +filename.
|
67
|
+
#
|
68
|
+
def self.potential_line?(filename, lineno)
|
69
|
+
potential_lines(filename).member?(lineno)
|
70
|
+
end
|
71
|
+
|
42
72
|
#
|
43
73
|
# True if there's no breakpoints
|
44
74
|
#
|
data/lib/byebug/command.rb
CHANGED
@@ -9,6 +9,11 @@ module Byebug
|
|
9
9
|
# Subclasses need to implement a `regexp` and an `execute` command.
|
10
10
|
#
|
11
11
|
class Command
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
include ParseFunctions
|
15
|
+
include FileFunctions
|
16
|
+
|
12
17
|
Subcmd = Struct.new(:name, :min, :help)
|
13
18
|
|
14
19
|
def initialize(state)
|
@@ -19,36 +24,49 @@ module Byebug
|
|
19
24
|
@match = regexp.match(input)
|
20
25
|
end
|
21
26
|
|
22
|
-
|
27
|
+
def_delegator :"Byebug.printer", :print, :pr
|
28
|
+
def_delegator :"Byebug.printer", :print_collection, :prc
|
29
|
+
def_delegator :"Byebug.printer", :print_variables, :prv
|
23
30
|
|
24
|
-
|
25
|
-
def_delegators :@state, :errmsg, :puts
|
31
|
+
protected
|
26
32
|
|
27
|
-
|
28
|
-
@state.confirm(msg) == 'y'
|
29
|
-
end
|
33
|
+
def_delegators :@state, :errmsg, :puts, :print, :confirm
|
30
34
|
|
35
|
+
#
|
36
|
+
# Evaluates a string containing Ruby code, using binding +b+. In case of
|
37
|
+
# error full stack trace and error are printed.
|
38
|
+
#
|
31
39
|
def bb_eval(str, b = get_binding)
|
32
|
-
eval(str
|
40
|
+
b.eval(str)
|
33
41
|
rescue StandardError, ScriptError => e
|
34
|
-
at =
|
35
|
-
|
36
|
-
at.
|
42
|
+
at = e.backtrace
|
43
|
+
locations = []
|
44
|
+
locations << "#{at.shift}: #{e.class} Exception(#{e.message})"
|
45
|
+
locations += at.map { |path| "\tfrom #{path}" }
|
46
|
+
|
47
|
+
errmsg(pr('eval.exception', text_message: locations.join("\n")))
|
37
48
|
nil
|
38
49
|
end
|
39
50
|
|
51
|
+
#
|
52
|
+
# Evaluates a string containing Ruby code, using binding +b+. In case of
|
53
|
+
# error, an error message with the exception is printed.
|
54
|
+
#
|
40
55
|
def bb_warning_eval(str, b = get_binding)
|
41
|
-
eval(str
|
56
|
+
b.eval(str)
|
42
57
|
rescue StandardError, ScriptError => e
|
43
|
-
|
58
|
+
text_message = "#{e.class} Exception: #{e.message}"
|
59
|
+
errmsg(pr('eval.exception', text_message: text_message))
|
44
60
|
nil
|
45
61
|
end
|
46
62
|
|
47
|
-
def get_binding(pos = @state.
|
63
|
+
def get_binding(pos = @state.frame)
|
48
64
|
@state.context ? @state.context.frame_binding(pos) : TOPLEVEL_BINDING
|
49
65
|
end
|
50
66
|
|
51
67
|
class << self
|
68
|
+
include StringFunctions
|
69
|
+
|
52
70
|
attr_accessor :allow_in_control
|
53
71
|
attr_writer :allow_in_post_mortem, :always_run
|
54
72
|
|
@@ -60,13 +78,11 @@ module Byebug
|
|
60
78
|
@always_run ||= 0
|
61
79
|
end
|
62
80
|
|
63
|
-
def help(
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
output += format_subcmds if defined? self::Subcommands
|
69
|
-
end
|
81
|
+
def help(subcmd = nil)
|
82
|
+
return format_subcmd(subcmd) if subcmd
|
83
|
+
|
84
|
+
output = description
|
85
|
+
output += format_subcmds if defined? self::Subcommands
|
70
86
|
output
|
71
87
|
end
|
72
88
|
|
@@ -106,18 +122,6 @@ module Byebug
|
|
106
122
|
def inherited(klass)
|
107
123
|
commands << klass
|
108
124
|
end
|
109
|
-
|
110
|
-
def load_commands
|
111
|
-
Dir.glob(File.expand_path('../commands/*.rb', __FILE__)).each do |file|
|
112
|
-
require file
|
113
|
-
end
|
114
|
-
|
115
|
-
Byebug.constants.grep(/Functions$/).map do |name|
|
116
|
-
include Byebug.const_get(name)
|
117
|
-
end
|
118
|
-
end
|
119
125
|
end
|
120
126
|
end
|
121
|
-
|
122
|
-
Command.load_commands
|
123
127
|
end
|