debug 1.4.0 → 1.9.2
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/CONTRIBUTING.md +210 -6
- data/Gemfile +2 -0
- data/LICENSE.txt +0 -0
- data/README.md +161 -85
- data/Rakefile +33 -10
- data/TODO.md +8 -8
- data/debug.gemspec +9 -7
- data/exe/rdbg +23 -4
- data/ext/debug/debug.c +111 -21
- data/ext/debug/extconf.rb +23 -0
- data/ext/debug/iseq_collector.c +2 -0
- data/lib/debug/abbrev_command.rb +77 -0
- data/lib/debug/breakpoint.rb +102 -74
- data/lib/debug/client.rb +46 -12
- data/lib/debug/color.rb +0 -0
- data/lib/debug/config.rb +129 -36
- data/lib/debug/console.rb +46 -40
- data/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/lib/debug/frame_info.rb +40 -25
- data/lib/debug/irb_integration.rb +37 -0
- data/lib/debug/local.rb +17 -11
- data/lib/debug/open.rb +0 -0
- data/lib/debug/open_nonstop.rb +0 -0
- data/lib/debug/prelude.rb +3 -2
- data/lib/debug/server.rb +126 -56
- data/lib/debug/server_cdp.rb +673 -248
- data/lib/debug/server_dap.rb +497 -261
- data/lib/debug/session.rb +899 -441
- data/lib/debug/source_repository.rb +122 -49
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +460 -155
- data/lib/debug/tracer.rb +10 -16
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +7 -2
- data/misc/README.md.erb +106 -56
- metadata +14 -24
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -24
- data/.github/ISSUE_TEMPLATE/custom.md +0 -10
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- data/.github/pull_request_template.md +0 -9
- data/.github/workflows/ruby.yml +0 -34
- data/.gitignore +0 -12
- data/bin/console +0 -14
- data/bin/gentest +0 -30
- data/bin/setup +0 -8
- data/lib/debug/bp.vim +0 -68
data/TODO.md
CHANGED
@@ -2,22 +2,22 @@
|
|
2
2
|
|
3
3
|
## Basic functionality
|
4
4
|
|
5
|
-
* Support Ractors
|
6
|
-
* Signal (SIGINT) trap handling
|
5
|
+
* Support Fibers and Ractors
|
7
6
|
|
8
7
|
## UI
|
9
8
|
|
9
|
+
* Multi-line support
|
10
10
|
* Completion for Ruby's code
|
11
11
|
* Interactive breakpoint setting
|
12
12
|
* Interactive record & play debugging
|
13
13
|
* irb integration
|
14
|
-
* Web browser integrated UI
|
15
|
-
* History file
|
16
14
|
|
17
15
|
## Debug command
|
18
16
|
|
19
|
-
* Breakpoints
|
20
|
-
* Lightweight pending method break points with Ruby 3.1 feature (TP:method_added)
|
21
17
|
* Watch points
|
22
|
-
* Lightweight watchpoints for instance variables with Ruby 3.
|
23
|
-
*
|
18
|
+
* Lightweight watchpoints for instance variables with Ruby 3.3 features (TP:ivar_set)
|
19
|
+
* Alias
|
20
|
+
|
21
|
+
## Debug port
|
22
|
+
|
23
|
+
* Debug port for monitoring
|
data/debug.gemspec
CHANGED
@@ -7,24 +7,26 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.email = ["ko1@atdot.net"]
|
8
8
|
|
9
9
|
spec.summary = %q{Debugging functionality for Ruby}
|
10
|
-
spec.description = %q{Debugging functionality for Ruby. This is completely rewritten debug.rb which was contained by the
|
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
17
|
|
18
18
|
# Specify which files should be added to the gem when it is released.
|
19
19
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
-
spec.files
|
21
|
-
`git ls-files -z`.split("\x0").reject
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
23
|
+
end
|
22
24
|
end
|
23
25
|
spec.bindir = "exe"
|
24
|
-
spec.executables = spec.files.grep(%r{
|
26
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
27
|
spec.require_paths = ["lib"]
|
26
28
|
spec.extensions = ['ext/debug/extconf.rb']
|
27
29
|
|
28
|
-
spec.add_dependency "irb", "
|
29
|
-
spec.add_dependency "reline", ">= 0.
|
30
|
+
spec.add_dependency "irb", "~> 1.10" # for irb:debug integration
|
31
|
+
spec.add_dependency "reline", ">= 0.3.8"
|
30
32
|
end
|
data/exe/rdbg
CHANGED
@@ -3,22 +3,41 @@
|
|
3
3
|
require_relative '../lib/debug/config'
|
4
4
|
config = DEBUGGER__::Config::parse_argv(ARGV)
|
5
5
|
|
6
|
-
|
6
|
+
# mode is not an actual configuration option
|
7
|
+
# it's only used to carry the result of parse_argv here
|
8
|
+
case config.delete(:mode)
|
7
9
|
when :start
|
8
10
|
require 'rbconfig'
|
9
11
|
|
10
12
|
libpath = File.join(File.expand_path(File.dirname(__dir__)), 'lib/debug')
|
11
|
-
start_mode = config[:
|
13
|
+
start_mode = config[:open] ? "open" : 'start'
|
12
14
|
cmd = config[:command] ? ARGV.shift : (ENV['RUBY'] || RbConfig.ruby)
|
13
15
|
|
16
|
+
if defined?($:.resolve_feature_path)
|
17
|
+
begin
|
18
|
+
_, sopath = $:.resolve_feature_path('debug/debug.so')
|
19
|
+
rescue LoadError
|
20
|
+
# raises LoadError before 3.1 (2.7 and 3.0)
|
21
|
+
else
|
22
|
+
sopath = File.dirname(File.dirname(sopath)) if sopath
|
23
|
+
end
|
24
|
+
else
|
25
|
+
# `$:.resolve_feature_path` is not defined in 2.6 or earlier.
|
26
|
+
so = "debug/debug.#{RbConfig::CONFIG['DLEXT']}"
|
27
|
+
sopath = $:.find {|dir| File.exist?(File.join(dir, so))}
|
28
|
+
end
|
29
|
+
added = "-r #{libpath}/#{start_mode}"
|
30
|
+
added = "-I #{sopath} #{added}" if sopath
|
31
|
+
rubyopt = ENV['RUBYOPT']
|
14
32
|
env = ::DEBUGGER__::Config.config_to_env_hash(config)
|
15
|
-
env['
|
33
|
+
env['RUBY_DEBUG_ADDED_RUBYOPT'] = added
|
34
|
+
env['RUBYOPT'] = "#{rubyopt} #{added}"
|
16
35
|
|
17
36
|
exec(env, cmd, *ARGV)
|
18
37
|
|
19
38
|
when :attach
|
20
39
|
require_relative "../lib/debug/client"
|
21
|
-
::DEBUGGER__::CONFIG.
|
40
|
+
::DEBUGGER__::CONFIG.set_config(**config)
|
22
41
|
|
23
42
|
begin
|
24
43
|
if ARGV.empty? && config[:port]
|
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,21 +62,34 @@ 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),
|
77
85
|
iseq,
|
78
86
|
rb_debug_inspector_frame_class_get(dc, i),
|
79
|
-
|
87
|
+
#ifdef RB_DEBUG_INSPECTOR_FRAME_DEPTH
|
88
|
+
rb_debug_inspector_frame_depth(dc, i)
|
89
|
+
#else
|
90
|
+
INT2FIX(len - i)
|
91
|
+
#endif
|
92
|
+
);
|
80
93
|
rb_ary_push(ary, e);
|
81
94
|
}
|
82
95
|
|
@@ -89,6 +102,13 @@ capture_frames(VALUE self, VALUE skip_path_prefix)
|
|
89
102
|
return rb_debug_inspector_open(di_body, (void *)skip_path_prefix);
|
90
103
|
}
|
91
104
|
|
105
|
+
#ifdef RB_DEBUG_INSPECTOR_FRAME_DEPTH
|
106
|
+
static VALUE
|
107
|
+
frame_depth(VALUE self)
|
108
|
+
{
|
109
|
+
return rb_debug_inspector_current_depth();
|
110
|
+
}
|
111
|
+
#else
|
92
112
|
static VALUE
|
93
113
|
frame_depth(VALUE self)
|
94
114
|
{
|
@@ -96,33 +116,89 @@ frame_depth(VALUE self)
|
|
96
116
|
VALUE bt = rb_make_backtrace();
|
97
117
|
return INT2FIX(RARRAY_LEN(bt));
|
98
118
|
}
|
119
|
+
#endif
|
120
|
+
|
121
|
+
|
122
|
+
// iseq
|
123
|
+
|
124
|
+
const rb_iseq_t *rb_iseqw_to_iseq(VALUE iseqw);
|
125
|
+
|
126
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
127
|
+
VALUE rb_iseq_type(const rb_iseq_t *);
|
128
|
+
|
129
|
+
static VALUE
|
130
|
+
iseq_type(VALUE iseqw)
|
131
|
+
{
|
132
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
133
|
+
return rb_iseq_type(iseq);
|
134
|
+
}
|
135
|
+
#endif
|
99
136
|
|
100
|
-
|
101
|
-
|
137
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
138
|
+
VALUE rb_iseq_parameters(const rb_iseq_t *, int is_proc);
|
139
|
+
|
140
|
+
static VALUE
|
141
|
+
iseq_parameters_symbols(VALUE iseqw)
|
102
142
|
{
|
103
|
-
|
104
|
-
VALUE
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
143
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
144
|
+
VALUE params = rb_iseq_parameters(iseq, 0);
|
145
|
+
VALUE ary = rb_ary_new();
|
146
|
+
|
147
|
+
static VALUE sym_ast, sym_astast, sym_amp;
|
148
|
+
|
149
|
+
if (sym_ast == 0) {
|
150
|
+
sym_ast = ID2SYM(rb_intern("*"));
|
151
|
+
sym_astast = ID2SYM(rb_intern("**"));
|
152
|
+
sym_amp = ID2SYM(rb_intern("&"));
|
153
|
+
}
|
154
|
+
|
155
|
+
for (long i=0; i<RARRAY_LEN(params); i++) {
|
156
|
+
VALUE e = RARRAY_AREF(params, i);
|
157
|
+
if (RARRAY_LEN(e) == 2) {
|
158
|
+
VALUE sym = RARRAY_AREF(e, 1);
|
159
|
+
if (sym != sym_ast &&
|
160
|
+
sym != sym_astast &&
|
161
|
+
sym != sym_amp) rb_ary_push(ary, RARRAY_AREF(e, 1));
|
162
|
+
}
|
112
163
|
}
|
164
|
+
|
165
|
+
return ary;
|
166
|
+
}
|
167
|
+
#endif
|
168
|
+
|
169
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
170
|
+
void rb_iseq_code_location(const rb_iseq_t *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);
|
171
|
+
|
172
|
+
static VALUE
|
173
|
+
iseq_first_line(VALUE iseqw)
|
174
|
+
{
|
175
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
176
|
+
int line;
|
177
|
+
rb_iseq_code_location(iseq, &line, NULL, NULL, NULL);
|
178
|
+
return INT2NUM(line);
|
113
179
|
}
|
114
180
|
|
115
181
|
static VALUE
|
116
|
-
|
182
|
+
iseq_last_line(VALUE iseqw)
|
117
183
|
{
|
118
|
-
|
184
|
+
const rb_iseq_t *iseq = rb_iseqw_to_iseq(iseqw);
|
185
|
+
int line;
|
186
|
+
rb_iseq_code_location(iseq, NULL, NULL, &line, NULL);
|
187
|
+
return INT2NUM(line);
|
119
188
|
}
|
189
|
+
#endif
|
120
190
|
|
191
|
+
#ifdef HAVE_RB_ISEQ
|
121
192
|
void Init_iseq_collector(void);
|
193
|
+
#endif
|
122
194
|
|
123
195
|
void
|
124
196
|
Init_debug(void)
|
125
197
|
{
|
198
|
+
#ifdef HAVE_RB_ISEQ
|
199
|
+
VALUE rb_mRubyVM = rb_const_get(rb_cObject, rb_intern("RubyVM"));
|
200
|
+
VALUE rb_cISeq = rb_const_get(rb_mRubyVM, rb_intern("InstructionSequence"));
|
201
|
+
#endif
|
126
202
|
rb_mDebugger = rb_const_get(rb_cObject, rb_intern("DEBUGGER__"));
|
127
203
|
rb_cFrameInfo = rb_const_get(rb_mDebugger, rb_intern("FrameInfo"));
|
128
204
|
|
@@ -132,7 +208,21 @@ Init_debug(void)
|
|
132
208
|
rb_gc_register_mark_object(rb_cFrameInfo);
|
133
209
|
rb_define_singleton_method(rb_mDebugger, "capture_frames", capture_frames, 1);
|
134
210
|
rb_define_singleton_method(rb_mDebugger, "frame_depth", frame_depth, 0);
|
135
|
-
rb_define_singleton_method(rb_mDebugger, "create_method_added_tracker", create_method_added_tracker, 0);
|
136
211
|
rb_define_const(rb_mDebugger, "SO_VERSION", rb_str_new2(RUBY_DEBUG_VERSION));
|
212
|
+
|
213
|
+
// iseq
|
214
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
215
|
+
rb_define_method(rb_cISeq, "type", iseq_type, 0);
|
216
|
+
#endif
|
217
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
218
|
+
rb_define_method(rb_cISeq, "parameters_symbols", iseq_parameters_symbols, 0);
|
219
|
+
#endif
|
220
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
221
|
+
rb_define_method(rb_cISeq, "first_line", iseq_first_line, 0);
|
222
|
+
rb_define_method(rb_cISeq, "last_line", iseq_last_line, 0);
|
223
|
+
#endif
|
224
|
+
|
225
|
+
#ifdef HAVE_RB_ISEQ
|
137
226
|
Init_iseq_collector();
|
227
|
+
#endif
|
138
228
|
}
|
data/ext/debug/extconf.rb
CHANGED
@@ -1,4 +1,27 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
require_relative '../../lib/debug/version'
|
3
3
|
File.write("debug_version.h", "#define RUBY_DEBUG_VERSION \"#{DEBUGGER__::VERSION}\"\n")
|
4
|
+
$distcleanfiles << "debug_version.h"
|
5
|
+
|
6
|
+
if defined? RubyVM
|
7
|
+
$defs << '-DHAVE_RB_ISEQ'
|
8
|
+
$defs << '-DHAVE_RB_ISEQ_PARAMETERS'
|
9
|
+
$defs << '-DHAVE_RB_ISEQ_CODE_LOCATION'
|
10
|
+
|
11
|
+
if RUBY_VERSION >= '3.1.0'
|
12
|
+
$defs << '-DHAVE_RB_ISEQ_TYPE'
|
13
|
+
end
|
14
|
+
else
|
15
|
+
# not on MRI
|
16
|
+
|
17
|
+
have_func "rb_iseq_parameters(NULL, 0)",
|
18
|
+
[["VALUE rb_iseq_parameters(void *, int is_proc);"]]
|
19
|
+
|
20
|
+
have_func "rb_iseq_code_location(NULL, NULL, NULL, NULL, NULL)",
|
21
|
+
[["void rb_iseq_code_location(void *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);"]]
|
22
|
+
# from Ruby 3.1
|
23
|
+
have_func "rb_iseq_type(NULL)",
|
24
|
+
[["VALUE rb_iseq_type(void *);"]]
|
25
|
+
end
|
26
|
+
|
4
27
|
create_makefile 'debug/debug'
|
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
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
module DEBUGGER__
|
3
|
+
class AbbrevCommand
|
4
|
+
class TrieNode
|
5
|
+
def initialize
|
6
|
+
@children = {}
|
7
|
+
@types = {} # set
|
8
|
+
end
|
9
|
+
|
10
|
+
def append c, type
|
11
|
+
trie = (@children[c] ||= TrieNode.new)
|
12
|
+
trie.add_type type
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](c)
|
16
|
+
@children[c]
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_type type
|
20
|
+
@types[type] = true
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def types
|
25
|
+
@types.keys
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
if @types.size == 1
|
30
|
+
@types.keys.first
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def candidates
|
37
|
+
@children.map{|c, n|
|
38
|
+
ss = n.candidates
|
39
|
+
ss.empty? ? c :
|
40
|
+
ss.map{|s|
|
41
|
+
c+s
|
42
|
+
}
|
43
|
+
}.flatten
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# config: { type: [commands...], ... }
|
48
|
+
def initialize config
|
49
|
+
@trie = TrieNode.new
|
50
|
+
build config
|
51
|
+
end
|
52
|
+
|
53
|
+
private def build config
|
54
|
+
config.each do |type, commands|
|
55
|
+
commands.each do |command|
|
56
|
+
trie = @trie
|
57
|
+
command.each_char do |c|
|
58
|
+
trie = trie.append(c, type)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def search str, if_none = nil
|
65
|
+
trie = @trie
|
66
|
+
str.each_char do |c|
|
67
|
+
if trie = trie[c]
|
68
|
+
return trie.type if trie.type
|
69
|
+
else
|
70
|
+
return if_none
|
71
|
+
end
|
72
|
+
end
|
73
|
+
yield trie.candidates.map{|s| str + s} if block_given?
|
74
|
+
if_none
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|