debug 1.4.0 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +195 -3
- data/Gemfile +1 -0
- data/README.md +55 -32
- data/Rakefile +28 -10
- data/debug.gemspec +7 -5
- data/exe/rdbg +7 -3
- data/ext/debug/debug.c +76 -14
- data/ext/debug/extconf.rb +22 -0
- data/lib/debug/breakpoint.rb +90 -66
- data/lib/debug/client.rb +21 -5
- data/lib/debug/config.rb +55 -24
- data/lib/debug/console.rb +43 -16
- data/lib/debug/frame_info.rb +32 -26
- data/lib/debug/local.rb +1 -1
- data/lib/debug/server.rb +105 -40
- data/lib/debug/server_cdp.rb +373 -152
- data/lib/debug/server_dap.rb +273 -170
- data/lib/debug/session.rb +450 -236
- data/lib/debug/source_repository.rb +104 -51
- data/lib/debug/thread_client.rb +252 -103
- data/lib/debug/tracer.rb +7 -12
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +34 -14
- metadata +6 -16
- 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/ext/debug/debug.c
CHANGED
@@ -97,32 +97,82 @@ frame_depth(VALUE self)
|
|
97
97
|
return INT2FIX(RARRAY_LEN(bt));
|
98
98
|
}
|
99
99
|
|
100
|
-
|
101
|
-
|
100
|
+
// iseq
|
101
|
+
|
102
|
+
const struct rb_iseq *rb_iseqw_to_iseq(VALUE iseqw);
|
103
|
+
|
104
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
105
|
+
VALUE rb_iseq_type(const struct rb_iseq *);
|
106
|
+
|
107
|
+
static VALUE
|
108
|
+
iseq_type(VALUE iseqw)
|
102
109
|
{
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
111
|
+
return rb_iseq_type(iseq);
|
112
|
+
}
|
113
|
+
#endif
|
114
|
+
|
115
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
116
|
+
VALUE rb_iseq_parameters(const struct rb_iseq *, int is_proc);
|
117
|
+
|
118
|
+
static VALUE
|
119
|
+
iseq_parameters_symbols(VALUE iseqw)
|
120
|
+
{
|
121
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
122
|
+
VALUE params = rb_iseq_parameters(iseq, 0);
|
123
|
+
VALUE ary = rb_ary_new();
|
124
|
+
|
125
|
+
static VALUE sym_ast, sym_astast, sym_amp;
|
126
|
+
|
127
|
+
if (sym_ast == 0) {
|
128
|
+
sym_ast = ID2SYM(rb_intern("*"));
|
129
|
+
sym_astast = ID2SYM(rb_intern("**"));
|
130
|
+
sym_amp = ID2SYM(rb_intern("&"));
|
112
131
|
}
|
132
|
+
|
133
|
+
for (long i=0; i<RARRAY_LEN(params); i++) {
|
134
|
+
VALUE e = RARRAY_AREF(params, i);
|
135
|
+
if (RARRAY_LEN(e) == 2) {
|
136
|
+
VALUE sym = RARRAY_AREF(e, 1);
|
137
|
+
if (sym != sym_ast &&
|
138
|
+
sym != sym_astast &&
|
139
|
+
sym != sym_amp) rb_ary_push(ary, RARRAY_AREF(e, 1));
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
return ary;
|
144
|
+
}
|
145
|
+
#endif
|
146
|
+
|
147
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
148
|
+
void rb_iseq_code_location(const struct rb_iseq *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);
|
149
|
+
|
150
|
+
static VALUE
|
151
|
+
iseq_first_line(VALUE iseqw)
|
152
|
+
{
|
153
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
154
|
+
int line;
|
155
|
+
rb_iseq_code_location(iseq, &line, NULL, NULL, NULL);
|
156
|
+
return INT2NUM(line);
|
113
157
|
}
|
114
158
|
|
115
159
|
static VALUE
|
116
|
-
|
160
|
+
iseq_last_line(VALUE iseqw)
|
117
161
|
{
|
118
|
-
|
162
|
+
const struct rb_iseq *iseq = rb_iseqw_to_iseq(iseqw);
|
163
|
+
int line;
|
164
|
+
rb_iseq_code_location(iseq, NULL, NULL, &line, NULL);
|
165
|
+
return INT2NUM(line);
|
119
166
|
}
|
167
|
+
#endif
|
120
168
|
|
121
169
|
void Init_iseq_collector(void);
|
122
170
|
|
123
171
|
void
|
124
172
|
Init_debug(void)
|
125
173
|
{
|
174
|
+
VALUE rb_mRubyVM = rb_const_get(rb_cObject, rb_intern("RubyVM"));
|
175
|
+
VALUE rb_cISeq = rb_const_get(rb_mRubyVM, rb_intern("InstructionSequence"));
|
126
176
|
rb_mDebugger = rb_const_get(rb_cObject, rb_intern("DEBUGGER__"));
|
127
177
|
rb_cFrameInfo = rb_const_get(rb_mDebugger, rb_intern("FrameInfo"));
|
128
178
|
|
@@ -132,7 +182,19 @@ Init_debug(void)
|
|
132
182
|
rb_gc_register_mark_object(rb_cFrameInfo);
|
133
183
|
rb_define_singleton_method(rb_mDebugger, "capture_frames", capture_frames, 1);
|
134
184
|
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
185
|
rb_define_const(rb_mDebugger, "SO_VERSION", rb_str_new2(RUBY_DEBUG_VERSION));
|
186
|
+
|
187
|
+
// iseq
|
188
|
+
#ifdef HAVE_RB_ISEQ_TYPE
|
189
|
+
rb_define_method(rb_cISeq, "type", iseq_type, 0);
|
190
|
+
#endif
|
191
|
+
#ifdef HAVE_RB_ISEQ_PARAMETERS
|
192
|
+
rb_define_method(rb_cISeq, "parameters_symbols", iseq_parameters_symbols, 0);
|
193
|
+
#endif
|
194
|
+
#ifdef HAVE_RB_ISEQ_CODE_LOCATION
|
195
|
+
rb_define_method(rb_cISeq, "first_line", iseq_first_line, 0);
|
196
|
+
rb_define_method(rb_cISeq, "last_line", iseq_last_line, 0);
|
197
|
+
#endif
|
198
|
+
|
137
199
|
Init_iseq_collector();
|
138
200
|
}
|
data/ext/debug/extconf.rb
CHANGED
@@ -1,4 +1,26 @@
|
|
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_PARAMETERS'
|
8
|
+
$defs << '-DHAVE_RB_ISEQ_CODE_LOCATION'
|
9
|
+
|
10
|
+
if RUBY_VERSION >= '3.1.0'
|
11
|
+
$defs << '-DHAVE_RB_ISEQ_TYPE'
|
12
|
+
end
|
13
|
+
else
|
14
|
+
# not on MRI
|
15
|
+
|
16
|
+
have_func "rb_iseq_parameters(NULL, 0)",
|
17
|
+
[["VALUE rb_iseq_parameters(void *, int is_proc);"]]
|
18
|
+
|
19
|
+
have_func "rb_iseq_code_location(NULL, NULL, NULL, NULL, NULL)",
|
20
|
+
[["void rb_iseq_code_location(void *, int *first_lineno, int *first_column, int *last_lineno, int *last_column);"]]
|
21
|
+
# from Ruby 3.1
|
22
|
+
have_func "rb_iseq_type(NULL)",
|
23
|
+
[["VALUE rb_iseq_type(void *);"]]
|
24
|
+
end
|
25
|
+
|
4
26
|
create_makefile 'debug/debug'
|
data/lib/debug/breakpoint.rb
CHANGED
@@ -8,9 +8,13 @@ module DEBUGGER__
|
|
8
8
|
|
9
9
|
attr_reader :key
|
10
10
|
|
11
|
-
def initialize do_enable
|
11
|
+
def initialize cond, command, path, do_enable: true
|
12
12
|
@deleted = false
|
13
13
|
|
14
|
+
@cond = cond
|
15
|
+
@command = command
|
16
|
+
@path = path
|
17
|
+
|
14
18
|
setup
|
15
19
|
enable if do_enable
|
16
20
|
end
|
@@ -82,8 +86,11 @@ module DEBUGGER__
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def skip_path?(path)
|
85
|
-
|
89
|
+
case @path
|
90
|
+
when Regexp
|
86
91
|
!path.match?(@path)
|
92
|
+
when String
|
93
|
+
!path.include?(@path)
|
87
94
|
else
|
88
95
|
super
|
89
96
|
end
|
@@ -108,7 +115,7 @@ module DEBUGGER__
|
|
108
115
|
@oneshot = oneshot
|
109
116
|
@key = [:iseq, @iseq.path, @iseq.first_lineno].freeze
|
110
117
|
|
111
|
-
super()
|
118
|
+
super(nil, nil, nil)
|
112
119
|
end
|
113
120
|
|
114
121
|
def setup
|
@@ -124,25 +131,30 @@ module DEBUGGER__
|
|
124
131
|
end
|
125
132
|
|
126
133
|
class LineBreakpoint < Breakpoint
|
127
|
-
attr_reader :path, :line, :iseq
|
134
|
+
attr_reader :path, :line, :iseq, :cond, :oneshot, :hook_call, :command
|
128
135
|
|
129
|
-
def
|
130
|
-
|
136
|
+
def self.copy bp, root_iseq
|
137
|
+
nbp = LineBreakpoint.new bp.path, bp.line,
|
138
|
+
cond: bp.cond, oneshot: bp.oneshot, hook_call: bp.hook_call,
|
139
|
+
command: bp.command, skip_activate: true
|
140
|
+
nbp.try_activate root_iseq
|
141
|
+
nbp
|
142
|
+
end
|
143
|
+
|
144
|
+
def initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil, skip_activate: false
|
131
145
|
@line = line
|
132
|
-
@cond = cond
|
133
146
|
@oneshot = oneshot
|
134
147
|
@hook_call = hook_call
|
135
|
-
@command = command
|
136
148
|
@pending = false
|
137
149
|
|
138
150
|
@iseq = nil
|
139
151
|
@type = nil
|
140
152
|
|
141
|
-
@key = [
|
153
|
+
@key = [path, @line].freeze
|
142
154
|
|
143
|
-
super()
|
155
|
+
super(cond, command, path)
|
144
156
|
|
145
|
-
try_activate
|
157
|
+
try_activate unless skip_activate
|
146
158
|
@pending = !@iseq
|
147
159
|
end
|
148
160
|
|
@@ -202,7 +214,7 @@ module DEBUGGER__
|
|
202
214
|
when events.include?(:RUBY_EVENT_END)
|
203
215
|
activate(iseq, :end, line)
|
204
216
|
else
|
205
|
-
# not
|
217
|
+
# not activated
|
206
218
|
end
|
207
219
|
end
|
208
220
|
|
@@ -212,42 +224,56 @@ module DEBUGGER__
|
|
212
224
|
|
213
225
|
NearestISeq = Struct.new(:iseq, :line, :events)
|
214
226
|
|
215
|
-
def
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
227
|
+
def iterate_iseq root_iseq
|
228
|
+
if root_iseq
|
229
|
+
is = [root_iseq]
|
230
|
+
while iseq = is.pop
|
231
|
+
yield iseq
|
232
|
+
iseq.each_child do |child_iseq|
|
233
|
+
is << child_iseq
|
234
|
+
end
|
235
|
+
end
|
236
|
+
else
|
237
|
+
ObjectSpace.each_iseq do |iseq|
|
238
|
+
if DEBUGGER__.compare_path((iseq.absolute_path || iseq.path), self.path) &&
|
239
|
+
iseq.first_lineno <= self.line &&
|
240
|
+
iseq.type != :ensure # ensure iseq is copied (duplicated)
|
241
|
+
yield iseq
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
222
246
|
|
223
|
-
|
224
|
-
|
247
|
+
def try_activate root_iseq = nil
|
248
|
+
nearest = nil # NearestISeq
|
249
|
+
iterate_iseq root_iseq do |iseq|
|
250
|
+
iseq.traceable_lines_norec(line_events = {})
|
251
|
+
lines = line_events.keys.sort
|
225
252
|
|
226
|
-
|
227
|
-
|
228
|
-
|
253
|
+
if !lines.empty? && lines.last >= line
|
254
|
+
nline = lines.bsearch{|l| line <= l}
|
255
|
+
events = line_events[nline]
|
229
256
|
|
230
|
-
|
257
|
+
next if events == [:RUBY_EVENT_B_CALL]
|
231
258
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
259
|
+
if @hook_call &&
|
260
|
+
events.include?(:RUBY_EVENT_CALL) &&
|
261
|
+
self.line == iseq.first_lineno
|
262
|
+
nline = iseq.first_lineno
|
263
|
+
end
|
237
264
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
end
|
265
|
+
if !nearest || ((line - nline).abs < (line - nearest.line).abs)
|
266
|
+
nearest = NearestISeq.new(iseq, nline, events)
|
267
|
+
else
|
268
|
+
if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno
|
269
|
+
if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) ||
|
270
|
+
(events.include?(:RUBY_EVENT_CALL))
|
271
|
+
nearest = NearestISeq.new(iseq, nline, events)
|
246
272
|
end
|
247
273
|
end
|
248
274
|
end
|
249
275
|
end
|
250
|
-
|
276
|
+
end
|
251
277
|
|
252
278
|
if nearest
|
253
279
|
activate_exact nearest.iseq, nearest.events, nearest.line
|
@@ -277,11 +303,7 @@ module DEBUGGER__
|
|
277
303
|
@key = [:catch, @pat].freeze
|
278
304
|
@last_exc = nil
|
279
305
|
|
280
|
-
|
281
|
-
@command = command
|
282
|
-
@path = path
|
283
|
-
|
284
|
-
super()
|
306
|
+
super(cond, command, path)
|
285
307
|
end
|
286
308
|
|
287
309
|
def setup
|
@@ -314,29 +336,41 @@ module DEBUGGER__
|
|
314
336
|
end
|
315
337
|
|
316
338
|
class CheckBreakpoint < Breakpoint
|
317
|
-
def initialize
|
318
|
-
@
|
319
|
-
@key = [:check, @expr].freeze
|
320
|
-
@path = path
|
339
|
+
def initialize cond:, command: nil, path: nil
|
340
|
+
@key = [:check, cond].freeze
|
321
341
|
|
322
|
-
super()
|
342
|
+
super(cond, command, path)
|
323
343
|
end
|
324
344
|
|
325
345
|
def setup
|
326
346
|
@tp = TracePoint.new(:line){|tp|
|
327
|
-
next if
|
328
|
-
next if tp.path.start_with? '<internal:'
|
347
|
+
next if SESSION.in_subsession? # TODO: Ractor support
|
329
348
|
next if ThreadClient.current.management?
|
330
349
|
next if skip_path?(tp.path)
|
331
350
|
|
332
|
-
if safe_eval
|
351
|
+
if need_suspend? safe_eval(tp.binding, @cond)
|
333
352
|
suspend
|
334
353
|
end
|
335
354
|
}
|
336
355
|
end
|
337
356
|
|
357
|
+
private def need_suspend? cond_result
|
358
|
+
map = ThreadClient.current.check_bp_fulfillment_map
|
359
|
+
if cond_result
|
360
|
+
if map[self]
|
361
|
+
false
|
362
|
+
else
|
363
|
+
map[self] = true
|
364
|
+
end
|
365
|
+
else
|
366
|
+
map[self] = false
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
338
370
|
def to_s
|
339
|
-
"#{generate_label("Check")}
|
371
|
+
s = "#{generate_label("Check")}"
|
372
|
+
s += super
|
373
|
+
s
|
340
374
|
end
|
341
375
|
end
|
342
376
|
|
@@ -348,10 +382,7 @@ module DEBUGGER__
|
|
348
382
|
|
349
383
|
@current = current
|
350
384
|
|
351
|
-
|
352
|
-
@command = command
|
353
|
-
@path = path
|
354
|
-
super()
|
385
|
+
super(cond, command, path)
|
355
386
|
end
|
356
387
|
|
357
388
|
def watch_eval(tp)
|
@@ -374,9 +405,6 @@ module DEBUGGER__
|
|
374
405
|
|
375
406
|
def setup
|
376
407
|
@tp = TracePoint.new(:line, :return, :b_return){|tp|
|
377
|
-
next if tp.path.start_with? __dir__
|
378
|
-
next if tp.path.start_with? '<internal:'
|
379
|
-
|
380
408
|
watch_eval(tp)
|
381
409
|
}
|
382
410
|
end
|
@@ -393,7 +421,7 @@ module DEBUGGER__
|
|
393
421
|
end
|
394
422
|
|
395
423
|
class MethodBreakpoint < Breakpoint
|
396
|
-
attr_reader :sig_method_name, :method
|
424
|
+
attr_reader :sig_method_name, :method, :klass
|
397
425
|
|
398
426
|
def initialize b, klass_name, op, method_name, cond: nil, command: nil, path: nil
|
399
427
|
@sig_klass_name = klass_name
|
@@ -404,13 +432,10 @@ module DEBUGGER__
|
|
404
432
|
|
405
433
|
@klass = nil
|
406
434
|
@method = nil
|
407
|
-
@cond = cond
|
408
435
|
@cond_class = nil
|
409
|
-
@command = command
|
410
|
-
@path = path
|
411
436
|
@key = "#{klass_name}#{op}#{method_name}".freeze
|
412
437
|
|
413
|
-
super(false)
|
438
|
+
super(cond, command, path, do_enable: false)
|
414
439
|
end
|
415
440
|
|
416
441
|
def setup
|
@@ -419,7 +444,6 @@ module DEBUGGER__
|
|
419
444
|
next if @cond_class && !tp.self.kind_of?(@cond_class)
|
420
445
|
|
421
446
|
caller_location = caller_locations(2, 1).first.to_s
|
422
|
-
next if caller_location.start_with?(__dir__)
|
423
447
|
next if skip_path?(caller_location)
|
424
448
|
|
425
449
|
suspend
|
data/lib/debug/client.rb
CHANGED
@@ -18,6 +18,10 @@ module DEBUGGER__
|
|
18
18
|
case name
|
19
19
|
when 'gen-sockpath'
|
20
20
|
puts DEBUGGER__.create_unix_domain_socket_name
|
21
|
+
when 'gen-portpath'
|
22
|
+
port_path = File.join(DEBUGGER__.unix_domain_socket_dir, 'tcp_port')
|
23
|
+
File.unlink port_path if File.exist?(port_path)
|
24
|
+
puts port_path
|
21
25
|
when 'list-socks'
|
22
26
|
cleanup_unix_domain_sockets
|
23
27
|
puts list_connections
|
@@ -76,7 +80,7 @@ module DEBUGGER__
|
|
76
80
|
|
77
81
|
def cleanup_unix_domain_sockets
|
78
82
|
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*') do |file|
|
79
|
-
if
|
83
|
+
if File.socket?(file) && (/-(\d+)-\d+$/ =~ file || /-(\d+)$/ =~ file)
|
80
84
|
begin
|
81
85
|
Process.kill(0, $1.to_i)
|
82
86
|
rescue Errno::EPERM
|
@@ -88,7 +92,9 @@ module DEBUGGER__
|
|
88
92
|
end
|
89
93
|
|
90
94
|
def list_connections
|
91
|
-
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*')
|
95
|
+
Dir.glob(DEBUGGER__.create_unix_domain_socket_name_prefix + '*').find_all do |path|
|
96
|
+
File.socket?(path)
|
97
|
+
end
|
92
98
|
end
|
93
99
|
end
|
94
100
|
|
@@ -115,7 +121,10 @@ module DEBUGGER__
|
|
115
121
|
@width = IO.console_size[1]
|
116
122
|
@width = 80 if @width == 0
|
117
123
|
|
118
|
-
send "version: #{VERSION}
|
124
|
+
send "version: #{VERSION} " +
|
125
|
+
"width: #{@width} " +
|
126
|
+
"cookie: #{CONFIG[:cookie] || '-'} " +
|
127
|
+
"nonstop: #{CONFIG[:nonstop] ? 'true' : 'false'}"
|
119
128
|
end
|
120
129
|
|
121
130
|
def deactivate
|
@@ -167,6 +176,8 @@ module DEBUGGER__
|
|
167
176
|
end
|
168
177
|
|
169
178
|
def connect
|
179
|
+
pre_commands = (CONFIG[:commands] || '').split(';;')
|
180
|
+
|
170
181
|
trap(:SIGINT){
|
171
182
|
send "pause"
|
172
183
|
}
|
@@ -175,7 +186,7 @@ module DEBUGGER__
|
|
175
186
|
trap(:SIGWINCH){
|
176
187
|
@width = IO.console_size[1]
|
177
188
|
}
|
178
|
-
rescue ArgumentError
|
189
|
+
rescue ArgumentError
|
179
190
|
@width = 80
|
180
191
|
end
|
181
192
|
|
@@ -193,7 +204,12 @@ module DEBUGGER__
|
|
193
204
|
prev_trap = trap(:SIGINT, 'DEFAULT')
|
194
205
|
|
195
206
|
begin
|
196
|
-
|
207
|
+
if pre_commands.empty?
|
208
|
+
line = readline
|
209
|
+
else
|
210
|
+
line = pre_commands.shift
|
211
|
+
puts "(rdbg:remote:command) #{line}"
|
212
|
+
end
|
197
213
|
rescue Interrupt
|
198
214
|
retry
|
199
215
|
ensure
|
data/lib/debug/config.rb
CHANGED
@@ -7,46 +7,50 @@ module DEBUGGER__
|
|
7
7
|
ERROR: 2,
|
8
8
|
WARN: 3,
|
9
9
|
INFO: 4,
|
10
|
+
DEBUG: 5
|
10
11
|
}.freeze
|
11
12
|
|
12
13
|
CONFIG_SET = {
|
13
14
|
# UI setting
|
14
|
-
log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger
|
15
|
-
show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint
|
16
|
-
show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint
|
17
|
-
use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)",
|
18
|
-
no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize
|
19
|
-
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT
|
20
|
-
no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library
|
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_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"],
|
18
|
+
use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"],
|
19
|
+
no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"],
|
20
|
+
no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"],
|
21
|
+
no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"],
|
22
|
+
no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"],
|
21
23
|
|
22
24
|
# control setting
|
23
|
-
skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths
|
24
|
-
skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines
|
25
|
-
keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it
|
26
|
-
postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug
|
27
|
-
fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)
|
28
|
-
sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal
|
25
|
+
skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path],
|
26
|
+
skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"],
|
27
|
+
keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"],
|
28
|
+
postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"],
|
29
|
+
fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"],
|
30
|
+
sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"],
|
29
31
|
|
30
32
|
# boot setting
|
31
|
-
nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool],
|
32
|
-
stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool],
|
33
|
+
nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"],
|
34
|
+
stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"],
|
33
35
|
init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"],
|
34
36
|
commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. commands should be separated by ';;'"],
|
35
|
-
no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool],
|
36
|
-
history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file
|
37
|
-
save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines
|
37
|
+
no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"],
|
38
|
+
history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"],
|
39
|
+
save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"],
|
38
40
|
|
39
41
|
# remote setting
|
40
42
|
port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"],
|
41
|
-
host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host
|
43
|
+
host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"],
|
42
44
|
sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"],
|
43
45
|
sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"],
|
46
|
+
local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map],
|
47
|
+
skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'],
|
44
48
|
cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"],
|
45
49
|
open_frontend: ['RUBY_DEBUG_OPEN_FRONTEND',"REMOTE: frontend used by open command (vscode, chrome, default: rdbg)."],
|
46
50
|
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))"],
|
47
51
|
|
48
52
|
# obsolete
|
49
|
-
parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork
|
53
|
+
parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"],
|
50
54
|
}.freeze
|
51
55
|
|
52
56
|
CONFIG_MAP = CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze
|
@@ -59,11 +63,23 @@ module DEBUGGER__
|
|
59
63
|
end
|
60
64
|
|
61
65
|
def initialize argv
|
66
|
+
@skip_all = false
|
67
|
+
|
62
68
|
if self.class.config
|
63
69
|
raise 'Can not make multiple configurations in one process'
|
64
70
|
end
|
65
71
|
|
66
|
-
|
72
|
+
config = self.class.parse_argv(argv)
|
73
|
+
|
74
|
+
# apply defaults
|
75
|
+
CONFIG_SET.each do |k, config_detail|
|
76
|
+
unless config.key?(k)
|
77
|
+
default_value = config_detail[3]
|
78
|
+
config[k] = parse_config_value(k, default_value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
update config
|
67
83
|
end
|
68
84
|
|
69
85
|
def inspect
|
@@ -78,6 +94,14 @@ module DEBUGGER__
|
|
78
94
|
set_config(key => val)
|
79
95
|
end
|
80
96
|
|
97
|
+
def skip_all
|
98
|
+
@skip_all = true
|
99
|
+
end
|
100
|
+
|
101
|
+
def skip?
|
102
|
+
@skip_all
|
103
|
+
end
|
104
|
+
|
81
105
|
def set_config(**kw)
|
82
106
|
conf = config.dup
|
83
107
|
kw.each{|k, v|
|
@@ -114,11 +138,13 @@ module DEBUGGER__
|
|
114
138
|
self.class.instance_variable_set(:@config, conf.freeze)
|
115
139
|
|
116
140
|
# Post process
|
117
|
-
if_updated old_conf, conf, :keep_alloc_site do |
|
141
|
+
if_updated old_conf, conf, :keep_alloc_site do |old, new|
|
118
142
|
if new
|
119
143
|
require 'objspace'
|
120
144
|
ObjectSpace.trace_object_allocations_start
|
121
|
-
|
145
|
+
end
|
146
|
+
|
147
|
+
if old && !new
|
122
148
|
ObjectSpace.trace_object_allocations_stop
|
123
149
|
end
|
124
150
|
end
|
@@ -215,6 +241,8 @@ module DEBUGGER__
|
|
215
241
|
e
|
216
242
|
end
|
217
243
|
}
|
244
|
+
when :path_map
|
245
|
+
valstr.split(',').map{|e| e.split(':')}
|
218
246
|
else
|
219
247
|
valstr
|
220
248
|
end
|
@@ -223,6 +251,7 @@ module DEBUGGER__
|
|
223
251
|
def self.parse_argv argv
|
224
252
|
config = {
|
225
253
|
mode: :start,
|
254
|
+
no_color: (nc = ENV['NO_COLOR']) && !nc.empty?,
|
226
255
|
}
|
227
256
|
CONFIG_MAP.each{|key, evname|
|
228
257
|
if val = ENV[evname]
|
@@ -361,6 +390,8 @@ module DEBUGGER__
|
|
361
390
|
case CONFIG_SET[key][2]
|
362
391
|
when :path
|
363
392
|
valstr = config[key].map{|e| e.kind_of?(Regexp) ? e.inspect : e}.join(':')
|
393
|
+
when :path_map
|
394
|
+
valstr = config[key].map{|e| e.join(':')}.join(',')
|
364
395
|
else
|
365
396
|
valstr = config[key].to_s
|
366
397
|
end
|
@@ -428,7 +459,7 @@ module DEBUGGER__
|
|
428
459
|
end
|
429
460
|
|
430
461
|
def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
|
431
|
-
user = ENV['USER'] || '
|
462
|
+
user = ENV['USER'] || 'UnknownUser'
|
432
463
|
File.join(base_dir, "ruby-debug-#{user}")
|
433
464
|
end
|
434
465
|
|