debug 1.4.0 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
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
- static void
101
- method_added_tracker(VALUE tpval, void *ptr)
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
- rb_trace_arg_t *arg = rb_tracearg_from_tracepoint(tpval);
104
- VALUE mid = rb_tracearg_callee_id(arg);
105
-
106
- if (RB_UNLIKELY(mid == ID2SYM(rb_intern("method_added")) ||
107
- mid == ID2SYM(rb_intern("singleton_method_added")))) {
108
- VALUE args[] = {
109
- tpval,
110
- };
111
- rb_funcallv(rb_mDebugger, rb_intern("method_added"), 1, args);
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
- create_method_added_tracker(VALUE self)
160
+ iseq_last_line(VALUE iseqw)
117
161
  {
118
- return rb_tracepoint_new(0, RUBY_EVENT_CALL, method_added_tracker, NULL);
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'
@@ -8,9 +8,13 @@ module DEBUGGER__
8
8
 
9
9
  attr_reader :key
10
10
 
11
- def initialize do_enable = true
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
- if @path
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 initialize path, line, cond: nil, oneshot: false, hook_call: true, command: nil
130
- @path = path
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 = [@path, @line].freeze
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 actiavated
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 try_activate
216
- nearest = nil # NearestISeq
217
-
218
- ObjectSpace.each_iseq{|iseq|
219
- if (iseq.absolute_path || iseq.path) == self.path &&
220
- iseq.first_lineno <= self.line &&
221
- iseq.type != :ensure # ensure iseq is copied (duplicated)
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
- iseq.traceable_lines_norec(line_events = {})
224
- lines = line_events.keys.sort
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
- if !lines.empty? && lines.last >= line
227
- nline = lines.bsearch{|l| line <= l}
228
- events = line_events[nline]
253
+ if !lines.empty? && lines.last >= line
254
+ nline = lines.bsearch{|l| line <= l}
255
+ events = line_events[nline]
229
256
 
230
- next if events == [:RUBY_EVENT_B_CALL]
257
+ next if events == [:RUBY_EVENT_B_CALL]
231
258
 
232
- if @hook_call &&
233
- events.include?(:RUBY_EVENT_CALL) &&
234
- self.line == iseq.first_lineno
235
- nline = iseq.first_lineno
236
- end
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
- if !nearest || ((line - nline).abs < (line - nearest.line).abs)
239
- nearest = NearestISeq.new(iseq, nline, events)
240
- else
241
- if @hook_call && nearest.iseq.first_lineno <= iseq.first_lineno
242
- if (nearest.line > line && !nearest.events.include?(:RUBY_EVENT_CALL)) ||
243
- (events.include?(:RUBY_EVENT_CALL))
244
- nearest = NearestISeq.new(iseq, nline, events)
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
- @cond = cond
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 expr, path
318
- @expr = expr.freeze
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 tp.path.start_with? __dir__
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 tp.binding, @expr
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")} #{@expr}"
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
- @cond = cond
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 /(\d+)$/ =~ file
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} width: #{@width} cookie: #{CONFIG[:cookie]}"
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 => e
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
- line = readline
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 (default: WARN)", :loglevel],
15
- show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint (default: 10 lines)", :int],
16
- show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint (default: 2 frames)", :int],
17
- use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool],
18
- no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize (default: false)", :bool],
19
- no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT (default: false)", :bool],
20
- no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library (default: false)", :bool],
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 (default: [])", :path],
24
- skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines (default: false)", :bool],
25
- keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it (default: false)", :bool],
26
- postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug (default: false)", :bool],
27
- fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child) (default: both)", :forkmode],
28
- sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal (default: disabled)"],
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 (default: ~/.rdbg_history)"],
37
- save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines (default: 10,000)"],
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 (localhost if not given)"],
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 (default: false)", :bool],
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
- update self.class.parse_argv(argv)
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 |_, new|
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
- else
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'] || 'ruby-debug'
462
+ user = ENV['USER'] || 'UnknownUser'
432
463
  File.join(base_dir, "ruby-debug-#{user}")
433
464
  end
434
465