byebug 4.0.4 → 4.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +5 -0
- data/GUIDE.md +63 -42
- data/lib/byebug/attacher.rb +5 -5
- data/lib/byebug/commands/break.rb +4 -5
- data/lib/byebug/commands/catch.rb +0 -2
- data/lib/byebug/commands/delete.rb +1 -1
- data/lib/byebug/commands/enable_disable.rb +1 -1
- data/lib/byebug/commands/info.rb +1 -1
- data/lib/byebug/commands/thread.rb +145 -0
- data/lib/byebug/commands/untracevar.rb +1 -1
- data/lib/byebug/context.rb +3 -0
- data/lib/byebug/core.rb +3 -47
- data/lib/byebug/helper.rb +23 -4
- data/lib/byebug/runner.rb +67 -22
- data/lib/byebug/version.rb +1 -1
- metadata +4 -4
- data/lib/byebug/commands/threads.rb +0 -237
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86c24793f077ce32dceea91c8bde07dce922a274
|
4
|
+
data.tar.gz: f166af0f5a9b01024978ebf2ebb5d9b7103d8a7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19d9a87a1f69496bdb00574437c3913b167d2da92d1b1b35c64412a70adfc8309f2bc78bdac5233bea310bd46543af2966b762453318e450ff6d73092626b16d
|
7
|
+
data.tar.gz: cfe46396685e6cec68816f38b70183317cf7585e1bbec594de6e670962151a5cd1eb4e1eb2483c0aafe43e94d741589c595c8d8e5a4cecb5124200b617c04b05
|
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -17,6 +17,11 @@ API and a lot of bugs have been recently corrected. Without this fixes,
|
|
17
17
|
`byebug` will fail to work properly, so make sure you have always the last
|
18
18
|
patch level releases of Ruby installed.
|
19
19
|
|
20
|
+
Also, if you are developing on linux, make sure you have the GNU indent utility
|
21
|
+
installed for automatic check of code style in C files. If you're developing in
|
22
|
+
MacOSX, just make sure you keep a consistent style if you edit the C-extension
|
23
|
+
files. Travis CI will do the automatic check anyways.
|
24
|
+
|
20
25
|
|
21
26
|
## Getting started
|
22
27
|
|
data/GUIDE.md
CHANGED
@@ -223,28 +223,28 @@ the output so that it nicely fits our screen.
|
|
223
223
|
(byebug) set width 80
|
224
224
|
Maximum width of byebug's output is 80
|
225
225
|
(byebug) ps private_methods
|
226
|
-
Array default_src_encoding open sleep
|
227
|
-
Complex define_method p spawn
|
228
|
-
Digest eval pp sprintf
|
229
|
-
Float exec print srand
|
230
|
-
Hash exit printf syscall
|
231
|
-
Integer exit! private system
|
232
|
-
Pathname fail proc test
|
233
|
-
Rational fork public throw
|
234
|
-
String format putc timeout
|
235
|
-
URI gem_original_require puts trace_var
|
236
|
-
__callee__ gets raise trap
|
226
|
+
Array default_src_encoding open sleep
|
227
|
+
Complex define_method p spawn
|
228
|
+
Digest eval pp sprintf
|
229
|
+
Float exec print srand
|
230
|
+
Hash exit printf syscall
|
231
|
+
Integer exit! private system
|
232
|
+
Pathname fail proc test
|
233
|
+
Rational fork public throw
|
234
|
+
String format putc timeout
|
235
|
+
URI gem_original_require puts trace_var
|
236
|
+
__callee__ gets raise trap
|
237
237
|
__dir__ global_variables rand untrace_var
|
238
|
-
__method__ include readline using
|
239
|
-
` initialize readlines warn
|
240
|
-
abort initialize_clone require y
|
241
|
-
at_exit initialize_copy require_relative
|
242
|
-
autoload initialize_dup respond_to_missing?
|
243
|
-
autoload? iterator? rubygems_require
|
244
|
-
binding lambda select
|
245
|
-
block_given? load set_trace_func
|
246
|
-
caller local_variables singleton_method_added
|
247
|
-
caller_locations loop singleton_method_removed
|
238
|
+
__method__ include readline using
|
239
|
+
` initialize readlines warn
|
240
|
+
abort initialize_clone require y
|
241
|
+
at_exit initialize_copy require_relative
|
242
|
+
autoload initialize_dup respond_to_missing?
|
243
|
+
autoload? iterator? rubygems_require
|
244
|
+
binding lambda select
|
245
|
+
block_given? load set_trace_func
|
246
|
+
caller local_variables singleton_method_added
|
247
|
+
caller_locations loop singleton_method_removed
|
248
248
|
catch method_missing singleton_method_undefined
|
249
249
|
(byebug)
|
250
250
|
```
|
@@ -500,7 +500,7 @@ Run options: --seed 31679
|
|
500
500
|
|
501
501
|
[2, 11] in test_triangle.rb
|
502
502
|
2: require_relative 'triangle.rb'
|
503
|
-
3:
|
503
|
+
3:
|
504
504
|
4: class TestTriangle < Minitest::Test
|
505
505
|
5: def test_basic
|
506
506
|
6: byebug
|
@@ -1035,7 +1035,7 @@ run a sleeping thread.
|
|
1035
1035
|
|
1036
1036
|
Now we can investigate the problem in the employer's side:
|
1037
1037
|
|
1038
|
-
|
1038
|
+
```bash
|
1039
1039
|
(byebug) s
|
1040
1040
|
[30, 39] in /path/to/company.rb
|
1041
1041
|
30:
|
@@ -1088,7 +1088,7 @@ Now we can investigate the problem in the employer's side:
|
|
1088
1088
|
39: show_off(@results.pop)
|
1089
1089
|
40: end
|
1090
1090
|
(byebug)
|
1091
|
-
|
1091
|
+
```
|
1092
1092
|
|
1093
1093
|
Now we can see the problem, the `@results` variable is always empty! The
|
1094
1094
|
employee forgot to leave the results in his manager's deck. We fix it by
|
@@ -1193,14 +1193,14 @@ get a line trace, `tracer` is most likely faster than `byebug`.
|
|
1193
1193
|
```bash
|
1194
1194
|
$ time byebug --trace --no-stop hanoi.rb > /dev/null
|
1195
1195
|
|
1196
|
-
real
|
1197
|
-
user
|
1198
|
-
sys
|
1196
|
+
real 0m0.743s
|
1197
|
+
user 0m0.668s
|
1198
|
+
sys 0m0.068s
|
1199
1199
|
$ time ruby -rtracer hanoi.rb > /dev/null
|
1200
1200
|
|
1201
|
-
real
|
1202
|
-
user
|
1203
|
-
sys
|
1201
|
+
real 0m0.077s
|
1202
|
+
user 0m0.072s
|
1203
|
+
sys 0m0.004s
|
1204
1204
|
```
|
1205
1205
|
|
1206
1206
|
### Byebug default options
|
@@ -1620,19 +1620,40 @@ will just call pretty-print.
|
|
1620
1620
|
:pretty_inspect,
|
1621
1621
|
:byebug]
|
1622
1622
|
(byebug) putl Kernel.instance_methods
|
1623
|
-
nil?
|
1624
|
-
===
|
1625
|
-
=~
|
1626
|
-
!~
|
1627
|
-
eql?
|
1628
|
-
hash
|
1623
|
+
nil? trust is_a?
|
1624
|
+
=== freeze tap
|
1625
|
+
=~ frozen? send
|
1626
|
+
!~ to_s public_send
|
1627
|
+
eql? inspect respond_to?
|
1628
|
+
hash methods extend
|
1629
|
+
<=> singleton_methods display
|
1630
|
+
class protected_methods method
|
1631
|
+
singleton_class private_methods public_method
|
1632
|
+
clone public_methods singleton_method
|
1633
|
+
dup instance_variables define_singleton_method
|
1634
|
+
itself instance_variable_get object_id
|
1635
|
+
taint instance_variable_set to_enum
|
1636
|
+
tainted? instance_variable_defined? enum_for
|
1637
|
+
untaint remove_instance_variable gem
|
1638
|
+
untrust instance_of? pretty_inspect
|
1639
|
+
untrusted? kind_of?
|
1629
1640
|
(byebug) ps Kernel.instance_methods
|
1630
|
-
!~
|
1631
|
-
<=>
|
1632
|
-
===
|
1633
|
-
=~
|
1634
|
-
|
1635
|
-
|
1641
|
+
!~ instance_of? public_send
|
1642
|
+
<=> instance_variable_defined? remove_instance_variable
|
1643
|
+
=== instance_variable_get respond_to?
|
1644
|
+
=~ instance_variable_set send
|
1645
|
+
class instance_variables singleton_class
|
1646
|
+
clone is_a? singleton_method
|
1647
|
+
define_singleton_method itself singleton_methods
|
1648
|
+
display kind_of? taint
|
1649
|
+
dup method tainted?
|
1650
|
+
enum_for methods tap
|
1651
|
+
eql? nil? to_enum
|
1652
|
+
extend object_id to_s
|
1653
|
+
freeze pretty_inspect trust
|
1654
|
+
frozen? private_methods untaint
|
1655
|
+
gem protected_methods untrust
|
1656
|
+
hash public_method untrusted?
|
1636
1657
|
```
|
1637
1658
|
|
1638
1659
|
Finally, if you need more advanced functionality from REPL's, you can enter
|
data/lib/byebug/attacher.rb
CHANGED
@@ -7,12 +7,12 @@ module Byebug
|
|
7
7
|
# events occur. Before entering byebug the init script is read.
|
8
8
|
#
|
9
9
|
def self.attach
|
10
|
-
|
10
|
+
unless started?
|
11
|
+
self.mode = :attached
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
run_init_script
|
13
|
+
start
|
14
|
+
run_init_script
|
15
|
+
end
|
16
16
|
|
17
17
|
current_context.step_out(2, true)
|
18
18
|
end
|
@@ -15,15 +15,14 @@ module Byebug
|
|
15
15
|
def execute
|
16
16
|
return puts(self.class.help) unless @match[1]
|
17
17
|
|
18
|
-
|
18
|
+
b = line_breakpoint(@match[1]) || method_breakpoint(@match[1])
|
19
|
+
|
19
20
|
if syntax_valid?(@match[2])
|
20
|
-
return puts(
|
21
|
-
pr('break.created', id: brkpt.id, file: brkpt.source, line: brkpt.pos)
|
22
|
-
)
|
21
|
+
return puts(pr('break.created', id: b.id, file: b.source, line: b.pos))
|
23
22
|
end
|
24
23
|
|
25
24
|
errmsg(pr('break.errors.expression', expr: @match[2]))
|
26
|
-
|
25
|
+
b.enabled = false
|
27
26
|
rescue => e
|
28
27
|
errmsg(e.message)
|
29
28
|
end
|
data/lib/byebug/commands/info.rb
CHANGED
@@ -176,7 +176,7 @@ module Byebug
|
|
176
176
|
def execute
|
177
177
|
return puts(self.class.help) unless @match[1]
|
178
178
|
|
179
|
-
args = @match[1].split(/
|
179
|
+
args = @match[1].split(/ +/)
|
180
180
|
param = args.shift
|
181
181
|
subcmd = Command.find(Subcommands, param)
|
182
182
|
return errmsg "Unknown info command #{param}\n" unless subcmd
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'byebug/command'
|
2
|
+
|
3
|
+
module Byebug
|
4
|
+
#
|
5
|
+
# Manipulation of Ruby threads
|
6
|
+
#
|
7
|
+
class ThreadCommand < Command
|
8
|
+
Subcommands = [
|
9
|
+
['current', 1, 'Shows current thread'],
|
10
|
+
['list', 1, 'Lists all threads'],
|
11
|
+
['resume', 1, 'Resumes execution of specified thread number'],
|
12
|
+
['stop', 2, 'Stops execution of specified thread number'],
|
13
|
+
['switch', 2, 'Switches execution to specified thread']
|
14
|
+
].map do |name, min, help|
|
15
|
+
Subcmd.new(name, min, help)
|
16
|
+
end
|
17
|
+
|
18
|
+
def regexp
|
19
|
+
/^\s* th(?:read)? (?:\s+ (.+))? \s*$/x
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute
|
23
|
+
return puts(self.class.help) unless @match[1]
|
24
|
+
|
25
|
+
name, thnum = @match[1].split(/ +/)[0..1]
|
26
|
+
subcmd = Command.find(Subcommands, name)
|
27
|
+
return errmsg("Unknown thread command '#{name}'\n") unless subcmd
|
28
|
+
|
29
|
+
send("thread_#{subcmd.name}", thnum)
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def names
|
34
|
+
%w(thread)
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
prettify <<-EOD
|
39
|
+
Commands to manipulate threads.
|
40
|
+
EOD
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def thread_list(thnum)
|
47
|
+
return errmsg("thread list doesn't need params") unless thnum.nil?
|
48
|
+
|
49
|
+
contexts = Byebug.contexts.sort_by(&:thnum)
|
50
|
+
|
51
|
+
thread_list = prc('thread.context', contexts) do |context, _|
|
52
|
+
thread_arguments(context)
|
53
|
+
end
|
54
|
+
|
55
|
+
print(thread_list)
|
56
|
+
end
|
57
|
+
|
58
|
+
def thread_current(thnum)
|
59
|
+
return errmsg("thread current doesn't need params") unless thnum.nil?
|
60
|
+
|
61
|
+
display_context(@state.context)
|
62
|
+
end
|
63
|
+
|
64
|
+
def thread_stop(thnum)
|
65
|
+
ctx, err = parse_thread_num_for_cmd('thread stop', thnum)
|
66
|
+
return errmsg(err) if err
|
67
|
+
|
68
|
+
ctx.suspend
|
69
|
+
display_context(ctx)
|
70
|
+
end
|
71
|
+
|
72
|
+
def thread_resume(thnum)
|
73
|
+
ctx, err = parse_thread_num_for_cmd('thread resume', thnum)
|
74
|
+
return errmsg(err) if err
|
75
|
+
return errmsg(pr('thread.errors.already_running')) unless ctx.suspended?
|
76
|
+
|
77
|
+
ctx.resume
|
78
|
+
display_context(ctx)
|
79
|
+
end
|
80
|
+
|
81
|
+
def thread_switch(thnum)
|
82
|
+
ctx, err = parse_thread_num_for_cmd('thread switch', thnum)
|
83
|
+
return errmsg(err) if err
|
84
|
+
|
85
|
+
display_context(ctx)
|
86
|
+
|
87
|
+
ctx.switch
|
88
|
+
@state.proceed
|
89
|
+
end
|
90
|
+
|
91
|
+
def display_context(context)
|
92
|
+
puts pr('thread.context', thread_arguments(context))
|
93
|
+
end
|
94
|
+
|
95
|
+
def thread_arguments(context)
|
96
|
+
status_flag = if context.suspended?
|
97
|
+
'$'
|
98
|
+
else
|
99
|
+
context.thread == Thread.current ? '+' : ' '
|
100
|
+
end
|
101
|
+
debug_flag = context.ignored? ? '!' : ' '
|
102
|
+
|
103
|
+
if context == Byebug.current_context
|
104
|
+
file_line = "#{@state.file}:#{@state.line}"
|
105
|
+
else
|
106
|
+
backtrace = context.thread.backtrace_locations
|
107
|
+
if backtrace && backtrace[0]
|
108
|
+
file_line = "#{backtrace[0].path}:#{backtrace[0].lineno}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
{
|
113
|
+
status_flag: status_flag,
|
114
|
+
debug_flag: debug_flag,
|
115
|
+
id: context.thnum,
|
116
|
+
thread: context.thread.inspect,
|
117
|
+
file_line: file_line || ''
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_thread_num(subcmd, arg)
|
122
|
+
thnum, err = get_int(arg, subcmd, 1)
|
123
|
+
return [nil, err] unless thnum
|
124
|
+
|
125
|
+
Byebug.contexts.find { |c| c.thnum == thnum }
|
126
|
+
end
|
127
|
+
|
128
|
+
def parse_thread_num_for_cmd(subcmd, arg)
|
129
|
+
c, err = parse_thread_num(subcmd, arg)
|
130
|
+
|
131
|
+
case
|
132
|
+
when err
|
133
|
+
[c, err]
|
134
|
+
when c.nil?
|
135
|
+
[nil, pr('thread.errors.no_thread')]
|
136
|
+
when @state.context == c
|
137
|
+
[c, pr('thread.errors.current_thread')]
|
138
|
+
when c.ignored?
|
139
|
+
[c, pr('thread.errors.wrong_action', subcmd: subcmd, arg: arg)]
|
140
|
+
else
|
141
|
+
[c, nil]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/byebug/context.rb
CHANGED
data/lib/byebug/core.rb
CHANGED
@@ -10,12 +10,6 @@ require 'byebug/printers/plain'
|
|
10
10
|
module Byebug
|
11
11
|
extend self
|
12
12
|
|
13
|
-
class NoScript < StandardError
|
14
|
-
end
|
15
|
-
|
16
|
-
class NonExistentScript < StandardError
|
17
|
-
end
|
18
|
-
|
19
13
|
#
|
20
14
|
# Configuration file used for startup commands. Default value is .byebugrc
|
21
15
|
#
|
@@ -27,15 +21,15 @@ module Byebug
|
|
27
21
|
attr_accessor :handler
|
28
22
|
self.handler = CommandProcessor.new
|
29
23
|
|
24
|
+
extend Forwardable
|
25
|
+
def_delegators :handler, :errmsg, :puts
|
26
|
+
|
30
27
|
#
|
31
28
|
# Main debugger's printer
|
32
29
|
#
|
33
30
|
attr_accessor :printer
|
34
31
|
self.printer = Printers::Plain.new
|
35
32
|
|
36
|
-
extend Forwardable
|
37
|
-
def_delegators :handler, :errmsg, :puts
|
38
|
-
|
39
33
|
#
|
40
34
|
# Running mode of the debugger. Can be either:
|
41
35
|
#
|
@@ -61,26 +55,6 @@ module Byebug
|
|
61
55
|
run_script(cwd_rc) if File.exist?(cwd_rc) && cwd_rc != home_rc
|
62
56
|
end
|
63
57
|
|
64
|
-
#
|
65
|
-
# Extracts debugged program from command line args
|
66
|
-
#
|
67
|
-
def setup_cmd_line_args
|
68
|
-
unless $PROGRAM_NAME.include?('bin/byebug')
|
69
|
-
self.mode = :attached
|
70
|
-
return
|
71
|
-
end
|
72
|
-
|
73
|
-
self.mode = :standalone
|
74
|
-
|
75
|
-
fail(NoScript, 'You must specify a program to debug...') if $ARGV.empty?
|
76
|
-
|
77
|
-
program = which($ARGV.shift)
|
78
|
-
program = which($ARGV.shift) if program == which('ruby')
|
79
|
-
fail(NonExistentScript, "The script doesn't exist") unless program
|
80
|
-
|
81
|
-
$PROGRAM_NAME = program
|
82
|
-
end
|
83
|
-
|
84
58
|
private
|
85
59
|
|
86
60
|
#
|
@@ -91,24 +65,6 @@ module Byebug
|
|
91
65
|
processor = ControlCommandProcessor.new(interface)
|
92
66
|
processor.process_commands
|
93
67
|
end
|
94
|
-
|
95
|
-
#
|
96
|
-
# Cross-platform way of finding an executable in the $PATH.
|
97
|
-
# Borrowed from: http://stackoverflow.com/questions/2108727
|
98
|
-
#
|
99
|
-
def which(cmd)
|
100
|
-
return File.expand_path(cmd) if File.exist?(cmd)
|
101
|
-
|
102
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
103
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
104
|
-
exts.each do |ext|
|
105
|
-
exe = File.join(path, "#{cmd}#{ext}")
|
106
|
-
return exe if File.executable?(exe) && !File.directory?(exe)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
nil
|
111
|
-
end
|
112
68
|
end
|
113
69
|
|
114
70
|
#
|
data/lib/byebug/helper.rb
CHANGED
@@ -88,12 +88,31 @@ module Byebug
|
|
88
88
|
end
|
89
89
|
|
90
90
|
#
|
91
|
-
# Returns true if code is syntactically correct for Ruby
|
91
|
+
# Returns true if code is syntactically correct for Ruby
|
92
92
|
#
|
93
93
|
def syntax_valid?(code)
|
94
|
-
|
95
|
-
|
96
|
-
|
94
|
+
return true unless code
|
95
|
+
|
96
|
+
without_stderr do
|
97
|
+
begin
|
98
|
+
RubyVM::InstructionSequence.compile(code)
|
99
|
+
true
|
100
|
+
rescue SyntaxError
|
101
|
+
false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Temporarily disable output to $stderr
|
108
|
+
#
|
109
|
+
def without_stderr
|
110
|
+
stderr = $stderr
|
111
|
+
$stderr.reopen(IO::NULL)
|
112
|
+
|
113
|
+
yield
|
114
|
+
ensure
|
115
|
+
$stderr.reopen(stderr)
|
97
116
|
end
|
98
117
|
|
99
118
|
#
|
data/lib/byebug/runner.rb
CHANGED
@@ -1,12 +1,28 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'English'
|
3
3
|
require 'byebug/core'
|
4
|
+
require 'byebug/helper'
|
4
5
|
|
5
6
|
module Byebug
|
6
7
|
#
|
7
8
|
# Responsible for starting the debugger when started from the command line.
|
8
9
|
#
|
9
10
|
class Runner
|
11
|
+
#
|
12
|
+
# Error class signaling absence of a script to debug
|
13
|
+
#
|
14
|
+
class NoScript < StandardError; end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Error class signaling a non existent script to debug
|
18
|
+
#
|
19
|
+
class NonExistentScript < StandardError; end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Error class signaling a script with invalid Ruby syntax
|
23
|
+
#
|
24
|
+
class InvalidScript < StandardError; end
|
25
|
+
|
10
26
|
#
|
11
27
|
# Special working modes that don't actually start the debugger.
|
12
28
|
#
|
@@ -36,27 +52,6 @@ module Byebug
|
|
36
52
|
EOB
|
37
53
|
end
|
38
54
|
|
39
|
-
#
|
40
|
-
# Debugs a script only if syntax checks okay.
|
41
|
-
#
|
42
|
-
def debug_program
|
43
|
-
check_syntax($PROGRAM_NAME)
|
44
|
-
|
45
|
-
status = Byebug.debug_load($PROGRAM_NAME, @stop)
|
46
|
-
Byebug.puts "#{status}\n#{status.backtrace}" if status
|
47
|
-
end
|
48
|
-
|
49
|
-
#
|
50
|
-
# Exits and outputs error message if syntax of the given program is invalid.
|
51
|
-
#
|
52
|
-
def check_syntax(program_name)
|
53
|
-
output = `ruby -c "#{program_name}" 2>&1`
|
54
|
-
return unless $CHILD_STATUS.exitstatus != 0
|
55
|
-
|
56
|
-
Byebug.errmsg(output)
|
57
|
-
exit($CHILD_STATUS.exitstatus)
|
58
|
-
end
|
59
|
-
|
60
55
|
#
|
61
56
|
# Starts byebug to debug a program
|
62
57
|
#
|
@@ -78,7 +73,7 @@ module Byebug
|
|
78
73
|
return
|
79
74
|
end
|
80
75
|
|
81
|
-
|
76
|
+
setup_cmd_line_args
|
82
77
|
|
83
78
|
loop do
|
84
79
|
debug_program
|
@@ -90,6 +85,11 @@ module Byebug
|
|
90
85
|
end
|
91
86
|
end
|
92
87
|
|
88
|
+
private
|
89
|
+
|
90
|
+
#
|
91
|
+
# Processes options passed from the command line
|
92
|
+
#
|
93
93
|
def prepare_options
|
94
94
|
OptionParser.new(banner, 25) do |opts|
|
95
95
|
opts.banner = banner
|
@@ -139,5 +139,50 @@ module Byebug
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Extracts debugged program from command line args
|
145
|
+
#
|
146
|
+
def setup_cmd_line_args
|
147
|
+
Byebug.mode = :standalone
|
148
|
+
|
149
|
+
fail(NoScript, 'You must specify a program to debug...') if $ARGV.empty?
|
150
|
+
|
151
|
+
program = which($ARGV.shift)
|
152
|
+
program = which($ARGV.shift) if program == which('ruby')
|
153
|
+
fail(NonExistentScript, "The script doesn't exist") unless program
|
154
|
+
|
155
|
+
$PROGRAM_NAME = program
|
156
|
+
end
|
157
|
+
|
158
|
+
include ParseFunctions
|
159
|
+
#
|
160
|
+
# Debugs a script only if syntax checks okay.
|
161
|
+
#
|
162
|
+
def debug_program
|
163
|
+
ok = syntax_valid?(File.read($PROGRAM_NAME))
|
164
|
+
fail(InvalidScript, 'The script has incorrect syntax') unless ok
|
165
|
+
|
166
|
+
error = Byebug.debug_load($PROGRAM_NAME, @stop)
|
167
|
+
Byebug.puts "#{status}\n#{status.backtrace}" if error
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Cross-platform way of finding an executable in the $PATH.
|
172
|
+
# Borrowed from: http://stackoverflow.com/questions/2108727
|
173
|
+
#
|
174
|
+
def which(cmd)
|
175
|
+
return File.expand_path(cmd) if File.exist?(cmd)
|
176
|
+
|
177
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
178
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
179
|
+
exts.each do |ext|
|
180
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
181
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
nil
|
186
|
+
end
|
142
187
|
end
|
143
188
|
end
|
data/lib/byebug/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: byebug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Rodriguez
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: columnize
|
@@ -102,7 +102,7 @@ files:
|
|
102
102
|
- lib/byebug/commands/show.rb
|
103
103
|
- lib/byebug/commands/source.rb
|
104
104
|
- lib/byebug/commands/stepping.rb
|
105
|
-
- lib/byebug/commands/
|
105
|
+
- lib/byebug/commands/thread.rb
|
106
106
|
- lib/byebug/commands/tracevar.rb
|
107
107
|
- lib/byebug/commands/undisplay.rb
|
108
108
|
- lib/byebug/commands/untracevar.rb
|
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
165
|
version: '0'
|
166
166
|
requirements: []
|
167
167
|
rubyforge_project:
|
168
|
-
rubygems_version: 2.4.
|
168
|
+
rubygems_version: 2.4.5
|
169
169
|
signing_key:
|
170
170
|
specification_version: 4
|
171
171
|
summary: Ruby 2.0 fast debugger - base + CLI
|
@@ -1,237 +0,0 @@
|
|
1
|
-
require 'byebug/command'
|
2
|
-
|
3
|
-
#
|
4
|
-
# TODO: Implement thread commands as a single command with subcommands, just
|
5
|
-
# like `info`, `var`, `enable` and `disable`. This allows consistent help
|
6
|
-
# format and we can go back to showing help for a single command in the `help`
|
7
|
-
# command.
|
8
|
-
#
|
9
|
-
module Byebug
|
10
|
-
#
|
11
|
-
# Utilities to assist commands related to threads.
|
12
|
-
#
|
13
|
-
module ThreadFunctions
|
14
|
-
def display_context(context, should_show_top_frame = true)
|
15
|
-
puts pr('thread.context',
|
16
|
-
thread_arguments(context, should_show_top_frame))
|
17
|
-
end
|
18
|
-
|
19
|
-
def thread_arguments(context, should_show_top_frame = true)
|
20
|
-
status_flag = if context.suspended?
|
21
|
-
'$'
|
22
|
-
else
|
23
|
-
context.thread == Thread.current ? '+' : ' '
|
24
|
-
end
|
25
|
-
debug_flag = context.ignored? ? '!' : ' '
|
26
|
-
|
27
|
-
if should_show_top_frame
|
28
|
-
if context == Byebug.current_context
|
29
|
-
file_line = "#{@state.file}:#{@state.line}"
|
30
|
-
else
|
31
|
-
backtrace = context.thread.backtrace_locations
|
32
|
-
if backtrace && backtrace[0]
|
33
|
-
file_line = "#{backtrace[0].path}:#{backtrace[0].lineno}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
{
|
38
|
-
status_flag: status_flag,
|
39
|
-
debug_flag: debug_flag,
|
40
|
-
id: context.thnum,
|
41
|
-
thread: context.thread.inspect,
|
42
|
-
file_line: file_line || ''
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse_thread_num(subcmd, arg)
|
47
|
-
thnum, err = get_int(arg, subcmd, 1)
|
48
|
-
return [nil, err] unless thnum
|
49
|
-
|
50
|
-
Byebug.contexts.find { |c| c.thnum == thnum }
|
51
|
-
end
|
52
|
-
|
53
|
-
def parse_thread_num_for_cmd(subcmd, arg)
|
54
|
-
c, err = parse_thread_num(subcmd, arg)
|
55
|
-
|
56
|
-
case
|
57
|
-
when err
|
58
|
-
[c, err]
|
59
|
-
when c.nil?
|
60
|
-
[nil, pr('thread.errors.no_thread')]
|
61
|
-
when @state.context == c
|
62
|
-
[c, pr('thread.errors.current_thread')]
|
63
|
-
when c.ignored?
|
64
|
-
[c, pr('thread.errors.wrong_action', subcmd: subcmd, arg: arg)]
|
65
|
-
else
|
66
|
-
[c, nil]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
#
|
72
|
-
# List current threads.
|
73
|
-
#
|
74
|
-
class ThreadListCommand < Command
|
75
|
-
include ThreadFunctions
|
76
|
-
|
77
|
-
self.allow_in_control = true
|
78
|
-
|
79
|
-
def regexp
|
80
|
-
/^\s* th(?:read)? \s+ l(?:ist)? \s*$/x
|
81
|
-
end
|
82
|
-
|
83
|
-
def execute
|
84
|
-
contexts = Byebug.contexts.sort_by(&:thnum)
|
85
|
-
|
86
|
-
thread_list = prc('thread.context', contexts) do |context, _|
|
87
|
-
thread_arguments(context)
|
88
|
-
end
|
89
|
-
|
90
|
-
print(thread_list)
|
91
|
-
end
|
92
|
-
|
93
|
-
class << self
|
94
|
-
def names
|
95
|
-
%w(thread)
|
96
|
-
end
|
97
|
-
|
98
|
-
def description
|
99
|
-
prettify <<-EOD
|
100
|
-
th[read] l[ist] Lists all threads.
|
101
|
-
EOD
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
#
|
107
|
-
# Show current thread.
|
108
|
-
#
|
109
|
-
class ThreadCurrentCommand < Command
|
110
|
-
include ThreadFunctions
|
111
|
-
|
112
|
-
def regexp
|
113
|
-
/^\s* th(?:read)? \s+ (?:cur(?:rent)?)? \s*$/x
|
114
|
-
end
|
115
|
-
|
116
|
-
def execute
|
117
|
-
display_context(@state.context)
|
118
|
-
end
|
119
|
-
|
120
|
-
class << self
|
121
|
-
def names
|
122
|
-
%w(thread)
|
123
|
-
end
|
124
|
-
|
125
|
-
def description
|
126
|
-
prettify <<-EOD
|
127
|
-
th[read] cur[rent] Shows current thread.
|
128
|
-
EOD
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
#
|
134
|
-
# Stop execution of a thread.
|
135
|
-
#
|
136
|
-
class ThreadStopCommand < Command
|
137
|
-
include ThreadFunctions
|
138
|
-
|
139
|
-
self.allow_in_control = true
|
140
|
-
self.allow_in_post_mortem = false
|
141
|
-
|
142
|
-
def regexp
|
143
|
-
/^\s* th(?:read)? \s+ stop \s* (\S*) \s*$/x
|
144
|
-
end
|
145
|
-
|
146
|
-
def execute
|
147
|
-
c, err = parse_thread_num_for_cmd('thread stop', @match[1])
|
148
|
-
return errmsg(err) if err
|
149
|
-
|
150
|
-
c.suspend
|
151
|
-
display_context(c)
|
152
|
-
end
|
153
|
-
|
154
|
-
class << self
|
155
|
-
def names
|
156
|
-
%w(thread)
|
157
|
-
end
|
158
|
-
|
159
|
-
def description
|
160
|
-
prettify <<-EOD
|
161
|
-
th[read] stop <n> Stops thread <n>.
|
162
|
-
EOD
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
#
|
168
|
-
# Resume execution of a thread.
|
169
|
-
#
|
170
|
-
class ThreadResumeCommand < Command
|
171
|
-
include ThreadFunctions
|
172
|
-
|
173
|
-
self.allow_in_control = true
|
174
|
-
self.allow_in_post_mortem = false
|
175
|
-
|
176
|
-
def regexp
|
177
|
-
/^\s* th(?:read)? \s+ resume \s* (\S*) \s*$/x
|
178
|
-
end
|
179
|
-
|
180
|
-
def execute
|
181
|
-
c, err = parse_thread_num_for_cmd('thread resume', @match[1])
|
182
|
-
return errmsg(err) if err
|
183
|
-
return errmsg pr('thread.errors.already_running') unless c.suspended?
|
184
|
-
|
185
|
-
c.resume
|
186
|
-
display_context(c)
|
187
|
-
end
|
188
|
-
|
189
|
-
class << self
|
190
|
-
def names
|
191
|
-
%w(thread)
|
192
|
-
end
|
193
|
-
|
194
|
-
def description
|
195
|
-
prettify <<-EOD
|
196
|
-
th[read] resume <n> Resumes thread <n>.
|
197
|
-
EOD
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
#
|
203
|
-
# Switch execution to a different thread.
|
204
|
-
#
|
205
|
-
class ThreadSwitchCommand < Command
|
206
|
-
include ThreadFunctions
|
207
|
-
|
208
|
-
self.allow_in_control = true
|
209
|
-
self.allow_in_post_mortem = false
|
210
|
-
|
211
|
-
def regexp
|
212
|
-
/^\s* th(?:read)? \s+ sw(?:itch)? (?:\s+(\S+))? \s*$/x
|
213
|
-
end
|
214
|
-
|
215
|
-
def execute
|
216
|
-
c, err = parse_thread_num_for_cmd('thread switch', @match[1])
|
217
|
-
return errmsg(err) if err
|
218
|
-
|
219
|
-
display_context(c)
|
220
|
-
|
221
|
-
c.switch
|
222
|
-
@state.proceed
|
223
|
-
end
|
224
|
-
|
225
|
-
class << self
|
226
|
-
def names
|
227
|
-
%w(thread)
|
228
|
-
end
|
229
|
-
|
230
|
-
def description
|
231
|
-
prettify <<-EOD
|
232
|
-
th[read] sw[itch] <n> Switches thread context to <n>.
|
233
|
-
EOD
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|