debug 1.8.0 → 1.11.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/Gemfile +1 -0
- data/README.md +177 -120
- data/debug.gemspec +4 -3
- data/ext/debug/debug.c +28 -14
- data/ext/debug/extconf.rb +1 -0
- data/ext/debug/iseq_collector.c +2 -0
- data/lib/debug/client.rb +3 -2
- data/lib/debug/config.rb +67 -39
- data/lib/debug/console.rb +31 -41
- data/lib/debug/frame_info.rb +3 -1
- data/lib/debug/irb_integration.rb +37 -0
- data/lib/debug/prelude.rb +1 -1
- data/lib/debug/server.rb +15 -4
- data/lib/debug/server_cdp.rb +11 -12
- data/lib/debug/server_dap.rb +4 -2
- data/lib/debug/session.rb +71 -38
- data/lib/debug/source_repository.rb +1 -1
- data/lib/debug/thread_client.rb +25 -22
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +168 -118
- metadata +12 -13
data/debug.gemspec
CHANGED
@@ -10,10 +10,11 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the ancient Ruby versions.}
|
11
11
|
spec.homepage = "https://github.com/ruby/debug"
|
12
12
|
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
16
|
spec.metadata["source_code_uri"] = spec.homepage
|
17
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/releases/tag/v#{spec.version}"
|
17
18
|
|
18
19
|
# Specify which files should be added to the gem when it is released.
|
19
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -27,6 +28,6 @@ Gem::Specification.new do |spec|
|
|
27
28
|
spec.require_paths = ["lib"]
|
28
29
|
spec.extensions = ['ext/debug/extconf.rb']
|
29
30
|
|
30
|
-
spec.add_dependency "irb", "
|
31
|
-
spec.add_dependency "reline", ">= 0.3.
|
31
|
+
spec.add_dependency "irb", "~> 1.10" # for irb:debug integration
|
32
|
+
spec.add_dependency "reline", ">= 0.3.8"
|
32
33
|
end
|
data/ext/debug/debug.c
CHANGED
@@ -8,13 +8,13 @@ static VALUE rb_mDebugger;
|
|
8
8
|
|
9
9
|
// iseq
|
10
10
|
typedef struct rb_iseq_struct rb_iseq_t;
|
11
|
+
const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw);
|
11
12
|
VALUE rb_iseq_realpath(const rb_iseq_t *iseq);
|
12
13
|
|
13
14
|
static VALUE
|
14
15
|
iseq_realpath(VALUE iseqw)
|
15
16
|
{
|
16
|
-
|
17
|
-
return rb_iseq_realpath(iseq);
|
17
|
+
return rb_iseq_realpath(rb_iseqw_to_iseq(iseqw));
|
18
18
|
}
|
19
19
|
|
20
20
|
static VALUE rb_cFrameInfo;
|
@@ -62,15 +62,23 @@ di_body(const rb_debug_inspector_t *dc, void *ptr)
|
|
62
62
|
long i;
|
63
63
|
|
64
64
|
for (i=1; i<len; i++) {
|
65
|
-
VALUE
|
65
|
+
VALUE e;
|
66
66
|
VALUE iseq = rb_debug_inspector_frame_iseq_get(dc, i);
|
67
|
+
VALUE loc = RARRAY_AREF(locs, i);
|
68
|
+
VALUE path;
|
67
69
|
|
68
70
|
if (!NIL_P(iseq)) {
|
69
|
-
|
70
|
-
|
71
|
+
path = iseq_realpath(iseq);
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
// C frame
|
75
|
+
path = rb_funcall(loc, rb_intern("path"), 0);
|
76
|
+
}
|
77
|
+
|
78
|
+
if (!NIL_P(path) && !NIL_P(skip_path_prefix) && str_start_with(path, skip_path_prefix)) {
|
79
|
+
continue;
|
71
80
|
}
|
72
81
|
|
73
|
-
loc = RARRAY_AREF(locs, i);
|
74
82
|
e = di_entry(loc,
|
75
83
|
rb_debug_inspector_frame_self_get(dc, i),
|
76
84
|
rb_debug_inspector_frame_binding_get(dc, i),
|
@@ -113,26 +121,26 @@ frame_depth(VALUE self)
|
|
113
121
|
|
114
122
|
// iseq
|
115
123
|
|
116
|
-
const
|
124
|
+
const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw);
|
117
125
|
|
118
126
|
#ifdef HAVE_RB_ISEQ_TYPE
|
119
|
-
VALUE rb_iseq_type(const
|
127
|
+
VALUE rb_iseq_type(const rb_iseq_t *);
|
120
128
|
|
121
129
|
static VALUE
|
122
130
|
iseq_type(VALUE iseqw)
|
123
131
|
{
|
124
|
-
const
|
132
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
125
133
|
return rb_iseq_type(iseq);
|
126
134
|
}
|
127
135
|
#endif
|
128
136
|
|
129
137
|
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
130
|
-
VALUE rb_iseq_parameters(const
|
138
|
+
VALUE rb_iseq_parameters(const rb_iseq_t *, int is_proc);
|
131
139
|
|
132
140
|
static VALUE
|
133
141
|
iseq_parameters_symbols(VALUE iseqw)
|
134
142
|
{
|
135
|
-
const
|
143
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
136
144
|
VALUE params = rb_iseq_parameters(iseq, 0);
|
137
145
|
VALUE ary = rb_ary_new();
|
138
146
|
|
@@ -159,12 +167,12 @@ iseq_parameters_symbols(VALUE iseqw)
|
|
159
167
|
#endif
|
160
168
|
|
161
169
|
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
162
|
-
void rb_iseq_code_location(const
|
170
|
+
void rb_iseq_code_location(const rb_iseq_t *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);
|
163
171
|
|
164
172
|
static VALUE
|
165
173
|
iseq_first_line(VALUE iseqw)
|
166
174
|
{
|
167
|
-
const
|
175
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
168
176
|
int line;
|
169
177
|
rb_iseq_code_location(iseq, &line, NULL, NULL, NULL);
|
170
178
|
return INT2NUM(line);
|
@@ -173,20 +181,24 @@ iseq_first_line(VALUE iseqw)
|
|
173
181
|
static VALUE
|
174
182
|
iseq_last_line(VALUE iseqw)
|
175
183
|
{
|
176
|
-
const
|
184
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
177
185
|
int line;
|
178
186
|
rb_iseq_code_location(iseq, NULL, NULL, &line, NULL);
|
179
187
|
return INT2NUM(line);
|
180
188
|
}
|
181
189
|
#endif
|
182
190
|
|
191
|
+
#ifdef HAVE_RB_ISEQ
|
183
192
|
void Init_iseq_collector(void);
|
193
|
+
#endif
|
184
194
|
|
185
195
|
void
|
186
196
|
Init_debug(void)
|
187
197
|
{
|
198
|
+
#ifdef HAVE_RB_ISEQ
|
188
199
|
VALUE rb_mRubyVM = rb_const_get(rb_cObject, rb_intern("RubyVM"));
|
189
200
|
VALUE rb_cISeq = rb_const_get(rb_mRubyVM, rb_intern("InstructionSequence"));
|
201
|
+
#endif
|
190
202
|
rb_mDebugger = rb_const_get(rb_cObject, rb_intern("DEBUGGER__"));
|
191
203
|
rb_cFrameInfo = rb_const_get(rb_mDebugger, rb_intern("FrameInfo"));
|
192
204
|
|
@@ -210,5 +222,7 @@ Init_debug(void)
|
|
210
222
|
rb_define_method(rb_cISeq, "last_line", iseq_last_line, 0);
|
211
223
|
#endif
|
212
224
|
|
225
|
+
#ifdef HAVE_RB_ISEQ
|
213
226
|
Init_iseq_collector();
|
227
|
+
#endif
|
214
228
|
}
|
data/ext/debug/extconf.rb
CHANGED
data/ext/debug/iseq_collector.c
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#include <ruby/ruby.h>
|
2
2
|
|
3
|
+
#ifdef HAVE_RB_ISEQ
|
3
4
|
VALUE rb_iseqw_new(VALUE v);
|
4
5
|
void rb_objspace_each_objects(
|
5
6
|
int (*callback)(void *start, void *end, size_t stride, void *data),
|
@@ -89,3 +90,4 @@ Init_iseq_collector(void)
|
|
89
90
|
rb_define_singleton_method(rb_mObjSpace, "each_iseq", each_iseq, 0);
|
90
91
|
rb_define_singleton_method(rb_mObjSpace, "count_iseq", count_iseq, 0);
|
91
92
|
}
|
93
|
+
#endif
|
data/lib/debug/client.rb
CHANGED
@@ -165,15 +165,16 @@ module DEBUGGER__
|
|
165
165
|
end
|
166
166
|
else
|
167
167
|
Client.cleanup_unix_domain_sockets
|
168
|
-
files = Client.list_connections
|
168
|
+
files = Client.list_connections
|
169
169
|
|
170
170
|
case files.size
|
171
171
|
when 0
|
172
172
|
$stderr.puts "No debug session is available."
|
173
173
|
exit
|
174
174
|
when 1
|
175
|
-
@s = Socket.unix(files.first
|
175
|
+
@s = Socket.unix(files.first)
|
176
176
|
else
|
177
|
+
files = Client.list_connections verbose: true
|
177
178
|
$stderr.puts "Please select a debug session:"
|
178
179
|
files.each{|(f, desc)|
|
179
180
|
$stderr.puts " #{File.basename(f)} (#{desc})"
|
data/lib/debug/config.rb
CHANGED
@@ -12,47 +12,52 @@ module DEBUGGER__
|
|
12
12
|
|
13
13
|
CONFIG_SET = {
|
14
14
|
# UI setting
|
15
|
-
log_level:
|
16
|
-
show_src_lines:
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"],
|
16
|
+
show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"],
|
17
|
+
show_src_lines_frame:['RUBY_DEBUG_SHOW_SRC_LINES_FRAME', "UI: Show n lines source code on frame operations", :int, "1"],
|
18
|
+
show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"],
|
19
|
+
show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"],
|
20
|
+
use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"],
|
21
|
+
no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"],
|
22
|
+
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"],
|
23
|
+
no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"],
|
24
|
+
no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"],
|
25
|
+
no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"],
|
26
|
+
no_repeat: ['RUBY_DEBUG_NO_REPEAT', "UI: Do not repeat last line when empty line",:bool, "false"],
|
27
|
+
irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"],
|
25
28
|
|
26
29
|
# control setting
|
27
|
-
skip_path:
|
28
|
-
skip_nosrc:
|
29
|
-
keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"],
|
30
|
-
postmortem:
|
31
|
-
fork_mode:
|
32
|
-
sigdump_sig:
|
30
|
+
skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path],
|
31
|
+
skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"],
|
32
|
+
keep_alloc_site: ['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"],
|
33
|
+
postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"],
|
34
|
+
fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"],
|
35
|
+
sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"],
|
33
36
|
|
34
37
|
# boot setting
|
35
|
-
nonstop:
|
36
|
-
stop_at_load:
|
37
|
-
init_script:
|
38
|
-
commands:
|
39
|
-
no_rc:
|
40
|
-
history_file:
|
41
|
-
save_history:
|
38
|
+
nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"],
|
39
|
+
stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"],
|
40
|
+
init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
|
41
|
+
commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"],
|
42
|
+
no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"],
|
43
|
+
history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file (default: ${XDG_STATE_HOME-~/.local/state}/rdbg/history)", :string, nil],
|
44
|
+
save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"],
|
42
45
|
|
43
46
|
# remote setting
|
44
|
-
open:
|
45
|
-
port:
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"],
|
48
|
+
port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
|
49
|
+
port_range: ['RUBY_DEBUG_PORT_RANGE', "REMOTE: TCP/IP remote debugging: length of port range"],
|
50
|
+
host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"],
|
51
|
+
sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
|
52
|
+
sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
|
53
|
+
local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map],
|
54
|
+
skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'],
|
55
|
+
cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
|
56
|
+
session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"],
|
57
|
+
chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"],
|
53
58
|
|
54
59
|
# obsolete
|
55
|
-
parent_on_fork:
|
60
|
+
parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"],
|
56
61
|
}.freeze
|
57
62
|
|
58
63
|
CONFIG_MAP = CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze
|
@@ -156,6 +161,22 @@ module DEBUGGER__
|
|
156
161
|
SESSION.set_no_sigint_hook old, new
|
157
162
|
end
|
158
163
|
end
|
164
|
+
|
165
|
+
if_updated old_conf, conf, :irb_console do |old, new|
|
166
|
+
if defined?(SESSION) && SESSION.active?
|
167
|
+
# irb_console is switched from true to false
|
168
|
+
if old
|
169
|
+
SESSION.deactivate_irb_integration
|
170
|
+
# irb_console is switched from false to true
|
171
|
+
else
|
172
|
+
if CONFIG[:open]
|
173
|
+
SESSION.instance_variable_get(:@ui).puts "\nIRB is not supported on the remote console."
|
174
|
+
else
|
175
|
+
SESSION.activate_irb_integration
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
159
180
|
end
|
160
181
|
|
161
182
|
private def if_updated old_conf, new_conf, key
|
@@ -334,12 +355,18 @@ module DEBUGGER__
|
|
334
355
|
o.on('--port=PORT', 'Listening TCP/IP port') do |port|
|
335
356
|
config[:port] = port
|
336
357
|
end
|
358
|
+
o.on('--port-range=PORT_RANGE', 'Number of ports to try to connect to') do |port_range|
|
359
|
+
config[:port_range] = port_range
|
360
|
+
end
|
337
361
|
o.on('--host=HOST', 'Listening TCP/IP host') do |host|
|
338
362
|
config[:host] = host
|
339
363
|
end
|
340
364
|
o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c|
|
341
365
|
config[:cookie] = c
|
342
366
|
end
|
367
|
+
o.on('--session-name=NAME', 'Session name') do |name|
|
368
|
+
config[:session_name] = name
|
369
|
+
end
|
343
370
|
|
344
371
|
rdbg = 'rdbg'
|
345
372
|
|
@@ -411,7 +438,6 @@ module DEBUGGER__
|
|
411
438
|
if argv.empty?
|
412
439
|
case
|
413
440
|
when have_shown_version && config[:mode] == :start
|
414
|
-
pp config
|
415
441
|
exit
|
416
442
|
end
|
417
443
|
end
|
@@ -458,7 +484,7 @@ module DEBUGGER__
|
|
458
484
|
require 'tmpdir'
|
459
485
|
|
460
486
|
if tmpdir = Dir.tmpdir
|
461
|
-
path = File.join(tmpdir, "
|
487
|
+
path = File.join(tmpdir, "rdbg-#{Process.uid}")
|
462
488
|
|
463
489
|
unless File.exist?(path)
|
464
490
|
d = Dir.mktmpdir
|
@@ -471,7 +497,7 @@ module DEBUGGER__
|
|
471
497
|
|
472
498
|
def self.unix_domain_socket_homedir
|
473
499
|
if home = ENV['HOME']
|
474
|
-
path = File.join(home, '.
|
500
|
+
path = File.join(home, '.rdbg-sock')
|
475
501
|
|
476
502
|
unless File.exist?(path)
|
477
503
|
Dir.mkdir(path, 0700)
|
@@ -495,12 +521,14 @@ module DEBUGGER__
|
|
495
521
|
end
|
496
522
|
|
497
523
|
def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
|
498
|
-
|
499
|
-
File.join(base_dir, "ruby-debug-#{user}")
|
524
|
+
File.join(base_dir, "rdbg")
|
500
525
|
end
|
501
526
|
|
502
527
|
def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
|
503
|
-
|
528
|
+
suffix = "-#{Process.pid}"
|
529
|
+
name = CONFIG[:session_name]
|
530
|
+
suffix << "-#{name}" if name
|
531
|
+
create_unix_domain_socket_name_prefix(base_dir) + suffix
|
504
532
|
end
|
505
533
|
|
506
534
|
## Help
|
data/lib/debug/console.rb
CHANGED
@@ -5,30 +5,9 @@ module DEBUGGER__
|
|
5
5
|
raise LoadError if CONFIG[:no_reline]
|
6
6
|
require 'reline'
|
7
7
|
|
8
|
-
# reline 0.2.7 or later is required.
|
9
|
-
raise LoadError if Reline::VERSION < '0.2.7'
|
10
|
-
|
11
8
|
require_relative 'color'
|
12
|
-
include Color
|
13
|
-
|
14
|
-
begin
|
15
|
-
prev = trap(:SIGWINCH, nil)
|
16
|
-
trap(:SIGWINCH, prev)
|
17
|
-
SIGWINCH_SUPPORTED = true
|
18
|
-
rescue ArgumentError
|
19
|
-
SIGWINCH_SUPPORTED = false
|
20
|
-
end
|
21
9
|
|
22
|
-
|
23
|
-
class ::Reline::LineEditor
|
24
|
-
m = Module.new do
|
25
|
-
def reset(prompt = '', encoding:)
|
26
|
-
super
|
27
|
-
Signal.trap(:SIGWINCH, nil)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
prepend m
|
31
|
-
end if SIGWINCH_SUPPORTED
|
10
|
+
include Color
|
32
11
|
|
33
12
|
def parse_input buff, commands
|
34
13
|
c, rest = get_command buff
|
@@ -56,10 +35,10 @@ module DEBUGGER__
|
|
56
35
|
Reline.prompt_proc = -> args, *kw do
|
57
36
|
case state = parse_input(args.first, commands)
|
58
37
|
when nil, :command
|
59
|
-
[prompt
|
38
|
+
[prompt]
|
60
39
|
when :ruby
|
61
|
-
[prompt.sub('rdbg'){colorize('ruby', [:RED])}]
|
62
|
-
end
|
40
|
+
[prompt.sub('rdbg'){colorize('ruby', [:RED])}]
|
41
|
+
end * args.size
|
63
42
|
end
|
64
43
|
|
65
44
|
Reline.completion_proc = -> given do
|
@@ -96,7 +75,7 @@ module DEBUGGER__
|
|
96
75
|
when nil
|
97
76
|
buff
|
98
77
|
when :ruby
|
99
|
-
colorize_code(buff
|
78
|
+
colorize_code(buff)
|
100
79
|
end
|
101
80
|
end unless CONFIG[:no_hint]
|
102
81
|
|
@@ -164,7 +143,7 @@ module DEBUGGER__
|
|
164
143
|
rescue LoadError
|
165
144
|
def readline prompt
|
166
145
|
print prompt
|
167
|
-
gets
|
146
|
+
$stdin.gets
|
168
147
|
end
|
169
148
|
|
170
149
|
def history
|
@@ -174,21 +153,28 @@ module DEBUGGER__
|
|
174
153
|
end
|
175
154
|
|
176
155
|
def history_file
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
156
|
+
case
|
157
|
+
when (path = CONFIG[:history_file]) && !path.empty?
|
158
|
+
path = File.expand_path(path)
|
159
|
+
when (path = File.expand_path("~/.rdbg_history")) && File.exist?(path) # for compatibility
|
160
|
+
# path
|
181
161
|
else
|
182
|
-
|
162
|
+
state_dir = ENV['XDG_STATE_HOME'] || File.join(Dir.home, '.local', 'state')
|
163
|
+
path = File.join(File.expand_path(state_dir), 'rdbg', 'history')
|
183
164
|
end
|
165
|
+
|
166
|
+
FileUtils.mkdir_p(File.dirname(path)) unless File.exist?(path)
|
167
|
+
path
|
184
168
|
end
|
185
169
|
|
186
170
|
FH = "# Today's OMIKUJI: "
|
187
171
|
|
188
172
|
def read_history_file
|
189
|
-
if history && File.exist?(path = history_file)
|
173
|
+
if history && File.exist?(path = history_file())
|
190
174
|
f = (['', 'DAI-', 'CHU-', 'SHO-'].map{|e| e+'KICHI'}+['KYO']).sample
|
191
|
-
|
175
|
+
# Read history file and scrub invalid characters to prevent encoding errors
|
176
|
+
lines = File.readlines(path).map(&:scrub)
|
177
|
+
["#{FH}#{f}".dup] + lines
|
192
178
|
else
|
193
179
|
[]
|
194
180
|
end
|
@@ -207,15 +193,17 @@ module DEBUGGER__
|
|
207
193
|
def deactivate
|
208
194
|
if history && @init_history_lines
|
209
195
|
added_records = history.to_a[@init_history_lines .. -1]
|
210
|
-
path = history_file
|
196
|
+
path = history_file()
|
211
197
|
max = CONFIG[:save_history]
|
212
198
|
|
213
199
|
if !added_records.empty? && !path.empty?
|
214
200
|
orig_records = read_history_file
|
215
|
-
open(history_file, 'w'){|f|
|
201
|
+
open(history_file(), 'w'){|f|
|
216
202
|
(orig_records + added_records).last(max).each{|line|
|
217
|
-
|
218
|
-
|
203
|
+
# Use scrub to handle encoding issues gracefully
|
204
|
+
scrubbed_line = line.scrub.strip
|
205
|
+
if !line.start_with?(FH) && !scrubbed_line.empty?
|
206
|
+
f.puts scrubbed_line
|
219
207
|
end
|
220
208
|
}
|
221
209
|
}
|
@@ -224,11 +212,13 @@ module DEBUGGER__
|
|
224
212
|
end
|
225
213
|
|
226
214
|
def load_history
|
227
|
-
read_history_file.
|
215
|
+
read_history_file.each{|line|
|
216
|
+
# Use scrub to handle encoding issues gracefully, then strip
|
217
|
+
line.scrub!
|
228
218
|
line.strip!
|
229
219
|
history << line unless line.empty?
|
230
|
-
}
|
220
|
+
} if history.empty?
|
221
|
+
history.count
|
231
222
|
end
|
232
223
|
end # class Console
|
233
224
|
end
|
234
|
-
|
data/lib/debug/frame_info.rb
CHANGED
@@ -86,7 +86,9 @@ module DEBUGGER__
|
|
86
86
|
|
87
87
|
def block_identifier
|
88
88
|
return unless frame_type == :block
|
89
|
-
|
89
|
+
re_match = location.label.match(BLOCK_LABL_REGEXP)
|
90
|
+
_, level, block_loc = re_match ? re_match.to_a : [nil, nil, location.label]
|
91
|
+
|
90
92
|
[level || "", block_loc]
|
91
93
|
end
|
92
94
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'irb'
|
4
|
+
|
5
|
+
module DEBUGGER__
|
6
|
+
module IrbPatch
|
7
|
+
def evaluate(line, line_no)
|
8
|
+
SESSION.send(:restart_all_threads)
|
9
|
+
super
|
10
|
+
# This is to communicate with the test framework so it can feed the next input
|
11
|
+
puts "INTERNAL_INFO: {}" if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal'
|
12
|
+
ensure
|
13
|
+
SESSION.send(:stop_all_threads)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ThreadClient
|
18
|
+
def activate_irb_integration
|
19
|
+
IRB.setup(location, argv: [])
|
20
|
+
workspace = IRB::WorkSpace.new(current_frame&.binding || TOPLEVEL_BINDING)
|
21
|
+
irb = IRB::Irb.new(workspace)
|
22
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
23
|
+
IRB::Debug.setup(irb)
|
24
|
+
IRB::Context.prepend(IrbPatch)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Session
|
29
|
+
def deactivate_irb_integration
|
30
|
+
Reline.completion_proc = nil
|
31
|
+
Reline.output_modifier_proc = nil
|
32
|
+
Reline.autocompletion = false
|
33
|
+
Reline.dig_perfect_match_proc = nil
|
34
|
+
reset_ui UI_LocalConsole.new
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/debug/prelude.rb
CHANGED
@@ -5,7 +5,7 @@ return if defined?(::DEBUGGER__::Session)
|
|
5
5
|
|
6
6
|
# Put the following line in your login script (e.g. ~/.bash_profile) with modified path:
|
7
7
|
#
|
8
|
-
# export RUBYOPT="-r /path/to/debug/prelude $
|
8
|
+
# export RUBYOPT="-r /path/to/debug/prelude ${RUBYOPT}"
|
9
9
|
#
|
10
10
|
module Kernel
|
11
11
|
def debugger(*a, up_level: 0, **kw)
|
data/lib/debug/server.rb
CHANGED
@@ -133,7 +133,7 @@ module DEBUGGER__
|
|
133
133
|
require 'etc'
|
134
134
|
|
135
135
|
check_cookie $1
|
136
|
-
@sock.puts "PID: #{Process.pid}, $0: #{$0}"
|
136
|
+
@sock.puts "PID: #{Process.pid}, $0: #{$0}, session_name: #{CONFIG[:session_name]}"
|
137
137
|
@sock.puts "debug #{VERSION} on #{RUBY_DESCRIPTION}"
|
138
138
|
@sock.puts "uname: #{Etc.uname.inspect}"
|
139
139
|
@sock.close
|
@@ -149,7 +149,9 @@ module DEBUGGER__
|
|
149
149
|
end
|
150
150
|
parse_option(params)
|
151
151
|
|
152
|
-
|
152
|
+
session_name = CONFIG[:session_name]
|
153
|
+
session_name_str = ", session_name:#{session_name}" if session_name
|
154
|
+
puts "DEBUGGER (client): Connected. PID:#{Process.pid}, $0:#{$0}#{session_name_str}"
|
153
155
|
puts "DEBUGGER (client): Type `Ctrl-C` to enter the debug console." unless @need_pause_at_first
|
154
156
|
puts
|
155
157
|
|
@@ -397,6 +399,13 @@ module DEBUGGER__
|
|
397
399
|
raise "Specify digits for port number"
|
398
400
|
end
|
399
401
|
end
|
402
|
+
@port_range = if @port.zero?
|
403
|
+
0
|
404
|
+
else
|
405
|
+
port_range_str = (CONFIG[:port_range] || "0").to_s
|
406
|
+
raise "Specify a positive integer <=16 for port range" unless port_range_str.match?(/\A\d+\z/) && port_range_str.to_i <= 16
|
407
|
+
port_range_str.to_i
|
408
|
+
end
|
400
409
|
@uuid = nil # for CDP
|
401
410
|
|
402
411
|
super()
|
@@ -410,7 +419,7 @@ module DEBUGGER__
|
|
410
419
|
DEBUGGER__.warn <<~EOS
|
411
420
|
With Chrome browser, type the following URL in the address-bar:
|
412
421
|
|
413
|
-
devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{@local_addr.inspect_sockaddr}/#{@uuid}
|
422
|
+
devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&noJavaScriptCompletion=true&ws=#{@local_addr.inspect_sockaddr}/#{@uuid}
|
414
423
|
|
415
424
|
EOS
|
416
425
|
end
|
@@ -450,7 +459,9 @@ module DEBUGGER__
|
|
450
459
|
end
|
451
460
|
end
|
452
461
|
rescue Errno::EADDRINUSE
|
453
|
-
|
462
|
+
number_of_retries = @port_range.zero? ? 10 : @port_range
|
463
|
+
if retry_cnt < number_of_retries
|
464
|
+
@port += 1 unless @port_range.zero?
|
454
465
|
retry_cnt += 1
|
455
466
|
sleep 0.1
|
456
467
|
retry
|