debug 1.7.2 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +47 -41
- data/debug.gemspec +3 -3
- data/ext/debug/debug.c +6 -0
- 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 +13 -6
- data/lib/debug/console.rb +8 -29
- data/lib/debug/dap_custom/traceInspector.rb +336 -0
- data/lib/debug/frame_info.rb +9 -0
- data/lib/debug/irb_integration.rb +27 -0
- data/lib/debug/server.rb +5 -3
- data/lib/debug/server_cdp.rb +11 -13
- data/lib/debug/server_dap.rb +191 -160
- data/lib/debug/session.rb +63 -29
- data/lib/debug/source_repository.rb +1 -1
- data/lib/debug/thread_client.rb +42 -24
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +41 -41
- metadata +12 -10
data/lib/debug/server_dap.rb
CHANGED
@@ -274,198 +274,225 @@ module DEBUGGER__
|
|
274
274
|
retry
|
275
275
|
end
|
276
276
|
|
277
|
+
def load_extensions req
|
278
|
+
if exts = req.dig('arguments', 'rdbgExtensions')
|
279
|
+
exts.each{|ext|
|
280
|
+
require_relative "dap_custom/#{File.basename(ext)}"
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
if scripts = req.dig('arguments', 'rdbgInitialScripts')
|
285
|
+
scripts.each do |script|
|
286
|
+
begin
|
287
|
+
eval(script)
|
288
|
+
rescue Exception => e
|
289
|
+
puts e.message
|
290
|
+
puts e.backtrace.inspect
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
277
296
|
def process
|
278
297
|
while req = recv_request
|
279
|
-
|
280
|
-
|
298
|
+
process_request(req)
|
299
|
+
end
|
300
|
+
ensure
|
301
|
+
send_event :terminated unless @sock.closed?
|
302
|
+
end
|
281
303
|
|
282
|
-
|
304
|
+
def process_request req
|
305
|
+
raise "not a request: #{req.inspect}" unless req['type'] == 'request'
|
306
|
+
args = req.dig('arguments')
|
283
307
|
|
284
|
-
|
285
|
-
when 'launch'
|
286
|
-
send_response req
|
287
|
-
# `launch` runs on debuggee on the same file system
|
288
|
-
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
|
289
|
-
@nonstop = true
|
308
|
+
case req['command']
|
290
309
|
|
291
|
-
|
292
|
-
|
293
|
-
|
310
|
+
## boot/configuration
|
311
|
+
when 'launch'
|
312
|
+
send_response req
|
313
|
+
# `launch` runs on debuggee on the same file system
|
314
|
+
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
|
315
|
+
@nonstop = true
|
294
316
|
|
295
|
-
|
296
|
-
@nonstop = true
|
297
|
-
else
|
298
|
-
@nonstop = false
|
299
|
-
end
|
317
|
+
load_extensions req
|
300
318
|
|
301
|
-
|
302
|
-
|
319
|
+
when 'attach'
|
320
|
+
send_response req
|
321
|
+
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
|
303
322
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
threadId: 1, # maybe ...
|
310
|
-
allThreadsStopped: true
|
311
|
-
end
|
312
|
-
end
|
323
|
+
if req.dig('arguments', 'nonstop') == true
|
324
|
+
@nonstop = true
|
325
|
+
else
|
326
|
+
@nonstop = false
|
327
|
+
end
|
313
328
|
|
314
|
-
|
315
|
-
req_path = args.dig('source', 'path')
|
316
|
-
path = UI_DAP.local_to_remote_path(req_path)
|
317
|
-
if path
|
318
|
-
SESSION.clear_line_breakpoints path
|
319
|
-
|
320
|
-
bps = []
|
321
|
-
args['breakpoints'].each{|bp|
|
322
|
-
line = bp['line']
|
323
|
-
if cond = bp['condition']
|
324
|
-
bps << SESSION.add_line_breakpoint(path, line, cond: cond)
|
325
|
-
else
|
326
|
-
bps << SESSION.add_line_breakpoint(path, line)
|
327
|
-
end
|
328
|
-
}
|
329
|
-
send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
|
330
|
-
else
|
331
|
-
send_response req, success: false, message: "#{req_path} is not available"
|
332
|
-
end
|
329
|
+
load_extensions req
|
333
330
|
|
334
|
-
|
335
|
-
|
331
|
+
when 'configurationDone'
|
332
|
+
send_response req
|
336
333
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
nil
|
347
|
-
end
|
348
|
-
{
|
349
|
-
verified: !bp.nil?,
|
350
|
-
message: bp.inspect,
|
351
|
-
}
|
352
|
-
}
|
334
|
+
if @nonstop
|
335
|
+
@q_msg << 'continue'
|
336
|
+
else
|
337
|
+
if SESSION.in_subsession?
|
338
|
+
send_event 'stopped', reason: 'pause',
|
339
|
+
threadId: 1, # maybe ...
|
340
|
+
allThreadsStopped: true
|
341
|
+
end
|
342
|
+
end
|
353
343
|
|
354
|
-
|
344
|
+
when 'setBreakpoints'
|
345
|
+
req_path = args.dig('source', 'path')
|
346
|
+
path = UI_DAP.local_to_remote_path(req_path)
|
347
|
+
if path
|
348
|
+
SESSION.clear_line_breakpoints path
|
349
|
+
|
350
|
+
bps = []
|
351
|
+
args['breakpoints'].each{|bp|
|
352
|
+
line = bp['line']
|
353
|
+
if cond = bp['condition']
|
354
|
+
bps << SESSION.add_line_breakpoint(path, line, cond: cond)
|
355
|
+
else
|
356
|
+
bps << SESSION.add_line_breakpoint(path, line)
|
357
|
+
end
|
358
|
+
}
|
359
|
+
send_response req, breakpoints: (bps.map do |bp| {verified: true,} end)
|
360
|
+
else
|
361
|
+
send_response req, success: false, message: "#{req_path} is not available"
|
362
|
+
end
|
355
363
|
|
356
|
-
|
357
|
-
|
364
|
+
when 'setFunctionBreakpoints'
|
365
|
+
send_response req
|
366
|
+
|
367
|
+
when 'setExceptionBreakpoints'
|
368
|
+
process_filter = ->(filter_id, cond = nil) {
|
369
|
+
bp =
|
370
|
+
case filter_id
|
371
|
+
when 'any'
|
372
|
+
SESSION.add_catch_breakpoint 'Exception', cond: cond
|
373
|
+
when 'RuntimeError'
|
374
|
+
SESSION.add_catch_breakpoint 'RuntimeError', cond: cond
|
375
|
+
else
|
376
|
+
nil
|
377
|
+
end
|
378
|
+
{
|
379
|
+
verified: !bp.nil?,
|
380
|
+
message: bp.inspect,
|
358
381
|
}
|
382
|
+
}
|
383
|
+
|
384
|
+
SESSION.clear_catch_breakpoints 'Exception', 'RuntimeError'
|
359
385
|
|
360
|
-
|
361
|
-
process_filter.call(
|
386
|
+
filters = args.fetch('filters').map {|filter_id|
|
387
|
+
process_filter.call(filter_id)
|
362
388
|
}
|
363
389
|
|
364
|
-
|
390
|
+
filters += args.fetch('filterOptions', {}).map{|bp_info|
|
391
|
+
process_filter.call(bp_info['filterId'], bp_info['condition'])
|
392
|
+
}
|
365
393
|
|
366
|
-
|
367
|
-
terminate = args.fetch("terminateDebuggee", false)
|
394
|
+
send_response req, breakpoints: filters
|
368
395
|
|
369
|
-
|
370
|
-
|
396
|
+
when 'disconnect'
|
397
|
+
terminate = args.fetch("terminateDebuggee", false)
|
371
398
|
|
372
|
-
|
373
|
-
|
374
|
-
@q_msg << 'kill!'
|
375
|
-
else
|
376
|
-
@q_msg << 'continue'
|
377
|
-
end
|
378
|
-
else
|
379
|
-
if terminate
|
380
|
-
@q_msg << 'kill!'
|
381
|
-
pause
|
382
|
-
end
|
383
|
-
end
|
399
|
+
SESSION.clear_all_breakpoints
|
400
|
+
send_response req
|
384
401
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
begin
|
391
|
-
@session.check_postmortem
|
392
|
-
@q_msg << 'n'
|
393
|
-
send_response req
|
394
|
-
rescue PostmortemError
|
395
|
-
send_response req,
|
396
|
-
success: false, message: 'postmortem mode',
|
397
|
-
result: "'Next' is not supported while postmortem mode"
|
398
|
-
end
|
399
|
-
when 'stepIn'
|
400
|
-
begin
|
401
|
-
@session.check_postmortem
|
402
|
-
@q_msg << 's'
|
403
|
-
send_response req
|
404
|
-
rescue PostmortemError
|
405
|
-
send_response req,
|
406
|
-
success: false, message: 'postmortem mode',
|
407
|
-
result: "'stepIn' is not supported while postmortem mode"
|
402
|
+
if SESSION.in_subsession?
|
403
|
+
if terminate
|
404
|
+
@q_msg << 'kill!'
|
405
|
+
else
|
406
|
+
@q_msg << 'continue'
|
408
407
|
end
|
409
|
-
|
410
|
-
|
411
|
-
@
|
412
|
-
|
413
|
-
send_response req
|
414
|
-
rescue PostmortemError
|
415
|
-
send_response req,
|
416
|
-
success: false, message: 'postmortem mode',
|
417
|
-
result: "'stepOut' is not supported while postmortem mode"
|
408
|
+
else
|
409
|
+
if terminate
|
410
|
+
@q_msg << 'kill!'
|
411
|
+
pause
|
418
412
|
end
|
419
|
-
|
413
|
+
end
|
414
|
+
|
415
|
+
## control
|
416
|
+
when 'continue'
|
417
|
+
@q_msg << 'c'
|
418
|
+
send_response req, allThreadsContinued: true
|
419
|
+
when 'next'
|
420
|
+
begin
|
421
|
+
@session.check_postmortem
|
422
|
+
@q_msg << 'n'
|
420
423
|
send_response req
|
421
|
-
|
422
|
-
|
424
|
+
rescue PostmortemError
|
425
|
+
send_response req,
|
426
|
+
success: false, message: 'postmortem mode',
|
427
|
+
result: "'Next' is not supported while postmortem mode"
|
428
|
+
end
|
429
|
+
when 'stepIn'
|
430
|
+
begin
|
431
|
+
@session.check_postmortem
|
432
|
+
@q_msg << 's'
|
423
433
|
send_response req
|
424
|
-
|
425
|
-
when 'reverseContinue'
|
434
|
+
rescue PostmortemError
|
426
435
|
send_response req,
|
427
|
-
success: false, message: '
|
428
|
-
result: "
|
429
|
-
|
430
|
-
|
436
|
+
success: false, message: 'postmortem mode',
|
437
|
+
result: "'stepIn' is not supported while postmortem mode"
|
438
|
+
end
|
439
|
+
when 'stepOut'
|
440
|
+
begin
|
441
|
+
@session.check_postmortem
|
442
|
+
@q_msg << 'fin'
|
443
|
+
send_response req
|
444
|
+
rescue PostmortemError
|
445
|
+
send_response req,
|
446
|
+
success: false, message: 'postmortem mode',
|
447
|
+
result: "'stepOut' is not supported while postmortem mode"
|
448
|
+
end
|
449
|
+
when 'terminate'
|
450
|
+
send_response req
|
451
|
+
exit
|
452
|
+
when 'pause'
|
453
|
+
send_response req
|
454
|
+
Process.kill(UI_ServerBase::TRAP_SIGNAL, Process.pid)
|
455
|
+
when 'reverseContinue'
|
456
|
+
send_response req,
|
457
|
+
success: false, message: 'cancelled',
|
458
|
+
result: "Reverse Continue is not supported. Only \"Step back\" is supported."
|
459
|
+
when 'stepBack'
|
460
|
+
@q_msg << req
|
431
461
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
}
|
462
|
+
## query
|
463
|
+
when 'threads'
|
464
|
+
send_response req, threads: SESSION.managed_thread_clients.map{|tc|
|
465
|
+
{ id: tc.id,
|
466
|
+
name: tc.name,
|
438
467
|
}
|
468
|
+
}
|
439
469
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
470
|
+
when 'evaluate'
|
471
|
+
expr = req.dig('arguments', 'expression')
|
472
|
+
if /\A\s*,(.+)\z/ =~ expr
|
473
|
+
dbg_expr = $1.strip
|
474
|
+
dbg_expr.split(';;') { |cmd| @q_msg << cmd }
|
445
475
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
@q_msg << req
|
451
|
-
end
|
452
|
-
when 'stackTrace',
|
453
|
-
'scopes',
|
454
|
-
'variables',
|
455
|
-
'source',
|
456
|
-
'completions'
|
476
|
+
send_response req,
|
477
|
+
result: "(rdbg:command) #{dbg_expr}",
|
478
|
+
variablesReference: 0
|
479
|
+
else
|
457
480
|
@q_msg << req
|
481
|
+
end
|
482
|
+
when 'stackTrace',
|
483
|
+
'scopes',
|
484
|
+
'variables',
|
485
|
+
'source',
|
486
|
+
'completions'
|
487
|
+
@q_msg << req
|
458
488
|
|
489
|
+
else
|
490
|
+
if respond_to? mid = "custom_dap_request_#{req['command']}"
|
491
|
+
__send__ mid, req
|
459
492
|
else
|
460
|
-
|
461
|
-
__send__ mid, req
|
462
|
-
else
|
463
|
-
raise "Unknown request: #{req.inspect}"
|
464
|
-
end
|
493
|
+
raise "Unknown request: #{req.inspect}"
|
465
494
|
end
|
466
495
|
end
|
467
|
-
ensure
|
468
|
-
send_event :terminated unless @sock.closed?
|
469
496
|
end
|
470
497
|
|
471
498
|
## called by the SESSION thread
|
@@ -625,6 +652,7 @@ module DEBUGGER__
|
|
625
652
|
expr = req.dig('arguments', 'expression')
|
626
653
|
|
627
654
|
if find_waiting_tc(tid)
|
655
|
+
restart_all_threads
|
628
656
|
request_tc [:dap, :evaluate, req, fid, expr, context]
|
629
657
|
else
|
630
658
|
fail_response req
|
@@ -701,6 +729,7 @@ module DEBUGGER__
|
|
701
729
|
register_vars result[:variables], tid
|
702
730
|
@ui.respond req, result
|
703
731
|
when :evaluate
|
732
|
+
stop_all_threads
|
704
733
|
message = result.delete :message
|
705
734
|
if message
|
706
735
|
@ui.respond req, success: false, message: message
|
@@ -759,7 +788,9 @@ module DEBUGGER__
|
|
759
788
|
|
760
789
|
def dap_eval b, expr, _context, prompt: '(repl_eval)'
|
761
790
|
begin
|
762
|
-
|
791
|
+
tp_allow_reentry do
|
792
|
+
b.eval(expr.to_s, prompt)
|
793
|
+
end
|
763
794
|
rescue Exception => e
|
764
795
|
e
|
765
796
|
end
|
@@ -867,7 +898,7 @@ module DEBUGGER__
|
|
867
898
|
}
|
868
899
|
when String
|
869
900
|
vars = [
|
870
|
-
variable('#
|
901
|
+
variable('#length', obj.length),
|
871
902
|
variable('#encoding', obj.encoding),
|
872
903
|
]
|
873
904
|
printed_str = value_inspect(obj)
|
@@ -1014,7 +1045,7 @@ module DEBUGGER__
|
|
1014
1045
|
klass = M_CLASS.bind_call(obj)
|
1015
1046
|
|
1016
1047
|
begin
|
1017
|
-
klass
|
1048
|
+
M_NAME.bind_call(klass) || klass.to_s
|
1018
1049
|
rescue Exception => e
|
1019
1050
|
"<Error: #{e.message} (#{e.backtrace.first}>"
|
1020
1051
|
end
|
data/lib/debug/session.rb
CHANGED
@@ -82,7 +82,7 @@ class RubyVM::InstructionSequence
|
|
82
82
|
def first_line
|
83
83
|
self.to_a[4][:code_location][0]
|
84
84
|
end unless method_defined?(:first_line)
|
85
|
-
end
|
85
|
+
end if defined?(RubyVM::InstructionSequence)
|
86
86
|
|
87
87
|
module DEBUGGER__
|
88
88
|
PresetCommands = Struct.new(:commands, :source, :auto_continue)
|
@@ -133,7 +133,7 @@ module DEBUGGER__
|
|
133
133
|
@commands = {}
|
134
134
|
@unsafe_context = false
|
135
135
|
|
136
|
-
@has_keep_script_lines = RubyVM.
|
136
|
+
@has_keep_script_lines = defined?(RubyVM.keep_script_lines)
|
137
137
|
|
138
138
|
@tp_load_script = TracePoint.new(:script_compiled){|tp|
|
139
139
|
eval_script = tp.eval_script unless @has_keep_script_lines
|
@@ -202,6 +202,11 @@ module DEBUGGER__
|
|
202
202
|
end
|
203
203
|
@tp_thread_end.enable
|
204
204
|
|
205
|
+
if CONFIG[:irb_console] && !CONFIG[:open]
|
206
|
+
require_relative "irb_integration"
|
207
|
+
thc.activate_irb_integration
|
208
|
+
end
|
209
|
+
|
205
210
|
# session start
|
206
211
|
q << true
|
207
212
|
session_server_main
|
@@ -256,6 +261,15 @@ module DEBUGGER__
|
|
256
261
|
@tc << req
|
257
262
|
end
|
258
263
|
|
264
|
+
def request_tc_with_restarted_threads(req)
|
265
|
+
restart_all_threads
|
266
|
+
request_tc(req)
|
267
|
+
end
|
268
|
+
|
269
|
+
def request_eval type, src
|
270
|
+
request_tc_with_restarted_threads [:eval, type, src]
|
271
|
+
end
|
272
|
+
|
259
273
|
def process_event evt
|
260
274
|
# variable `@internal_info` is only used for test
|
261
275
|
tc, output, ev, @internal_info, *ev_args = evt
|
@@ -314,7 +328,7 @@ module DEBUGGER__
|
|
314
328
|
if @displays.empty?
|
315
329
|
wait_command_loop
|
316
330
|
else
|
317
|
-
|
331
|
+
request_eval :display, @displays
|
318
332
|
end
|
319
333
|
when :result
|
320
334
|
raise "[BUG] not in subsession" if @subsession_stack.empty?
|
@@ -329,6 +343,7 @@ module DEBUGGER__
|
|
329
343
|
end
|
330
344
|
end
|
331
345
|
|
346
|
+
stop_all_threads
|
332
347
|
when :method_breakpoint, :watch_breakpoint
|
333
348
|
bp = ev_args[1]
|
334
349
|
if bp
|
@@ -342,6 +357,7 @@ module DEBUGGER__
|
|
342
357
|
obj_inspect = ev_args[2]
|
343
358
|
opt = ev_args[3]
|
344
359
|
add_tracer ObjectTracer.new(@ui, obj_id, obj_inspect, **opt)
|
360
|
+
stop_all_threads
|
345
361
|
else
|
346
362
|
stop_all_threads
|
347
363
|
end
|
@@ -685,15 +701,15 @@ module DEBUGGER__
|
|
685
701
|
register_command 'bt', 'backtrace', unsafe: false do |arg|
|
686
702
|
case arg
|
687
703
|
when /\A(\d+)\z/
|
688
|
-
|
704
|
+
request_tc_with_restarted_threads [:show, :backtrace, arg.to_i, nil]
|
689
705
|
when /\A\/(.*)\/\z/
|
690
706
|
pattern = $1
|
691
|
-
|
707
|
+
request_tc_with_restarted_threads [:show, :backtrace, nil, Regexp.compile(pattern)]
|
692
708
|
when /\A(\d+)\s+\/(.*)\/\z/
|
693
709
|
max, pattern = $1, $2
|
694
|
-
|
710
|
+
request_tc_with_restarted_threads [:show, :backtrace, max.to_i, Regexp.compile(pattern)]
|
695
711
|
else
|
696
|
-
|
712
|
+
request_tc_with_restarted_threads [:show, :backtrace, nil, nil]
|
697
713
|
end
|
698
714
|
end
|
699
715
|
|
@@ -810,15 +826,15 @@ module DEBUGGER__
|
|
810
826
|
|
811
827
|
case sub
|
812
828
|
when nil
|
813
|
-
|
829
|
+
request_tc_with_restarted_threads [:show, :default, pat] # something useful
|
814
830
|
when :locals
|
815
|
-
|
831
|
+
request_tc_with_restarted_threads [:show, :locals, pat]
|
816
832
|
when :ivars
|
817
|
-
|
833
|
+
request_tc_with_restarted_threads [:show, :ivars, pat, opt]
|
818
834
|
when :consts
|
819
|
-
|
835
|
+
request_tc_with_restarted_threads [:show, :consts, pat, opt]
|
820
836
|
when :globals
|
821
|
-
|
837
|
+
request_tc_with_restarted_threads [:show, :globals, pat]
|
822
838
|
when :threads
|
823
839
|
thread_list
|
824
840
|
:retry
|
@@ -838,7 +854,7 @@ module DEBUGGER__
|
|
838
854
|
# * Show you available methods and instance variables of the given object.
|
839
855
|
# * If the object is a class/module, it also lists its constants.
|
840
856
|
register_command 'outline', 'o', 'ls', unsafe: false do |arg|
|
841
|
-
|
857
|
+
request_tc_with_restarted_threads [:show, :outline, arg]
|
842
858
|
end
|
843
859
|
|
844
860
|
# * `display`
|
@@ -848,9 +864,9 @@ module DEBUGGER__
|
|
848
864
|
register_command 'display', postmortem: false do |arg|
|
849
865
|
if arg && !arg.empty?
|
850
866
|
@displays << arg
|
851
|
-
|
867
|
+
request_eval :try_display, @displays
|
852
868
|
else
|
853
|
-
|
869
|
+
request_eval :display, @displays
|
854
870
|
end
|
855
871
|
end
|
856
872
|
|
@@ -864,7 +880,7 @@ module DEBUGGER__
|
|
864
880
|
if @displays[n = $1.to_i]
|
865
881
|
@displays.delete_at n
|
866
882
|
end
|
867
|
-
|
883
|
+
request_eval :display, @displays
|
868
884
|
when nil
|
869
885
|
if ask "clear all?", 'N'
|
870
886
|
@displays.clear
|
@@ -925,10 +941,11 @@ module DEBUGGER__
|
|
925
941
|
# * Invoke `irb` on the current frame.
|
926
942
|
register_command 'irb' do |arg|
|
927
943
|
if @ui.remote?
|
928
|
-
@ui.puts "not supported on the remote console."
|
944
|
+
@ui.puts "\nIRB is not supported on the remote console."
|
929
945
|
:retry
|
946
|
+
else
|
947
|
+
request_eval :irb, nil
|
930
948
|
end
|
931
|
-
request_eval :irb, nil
|
932
949
|
end
|
933
950
|
|
934
951
|
### Trace
|
@@ -983,7 +1000,7 @@ module DEBUGGER__
|
|
983
1000
|
:retry
|
984
1001
|
|
985
1002
|
when /\Aobject\s+(.+)/
|
986
|
-
|
1003
|
+
request_tc_with_restarted_threads [:trace, :object, $1.strip, {pattern: pattern, into: into}]
|
987
1004
|
|
988
1005
|
when /\Aoff\s+(\d+)\z/
|
989
1006
|
if t = @tracers.values[$1.to_i]
|
@@ -1164,11 +1181,6 @@ module DEBUGGER__
|
|
1164
1181
|
return :retry
|
1165
1182
|
end
|
1166
1183
|
|
1167
|
-
def request_eval type, src
|
1168
|
-
restart_all_threads
|
1169
|
-
request_tc [:eval, type, src]
|
1170
|
-
end
|
1171
|
-
|
1172
1184
|
def step_command type, arg
|
1173
1185
|
if type == :until
|
1174
1186
|
leave_subsession [:step, type, arg]
|
@@ -1739,15 +1751,19 @@ module DEBUGGER__
|
|
1739
1751
|
# check breakpoints
|
1740
1752
|
if file_path
|
1741
1753
|
@bps.find_all do |_key, bp|
|
1742
|
-
LineBreakpoint === bp && bp.path_is?(file_path)
|
1754
|
+
LineBreakpoint === bp && bp.path_is?(file_path) && (iseq.first_lineno..iseq.last_line).cover?(bp.line)
|
1743
1755
|
end.each do |_key, bp|
|
1744
1756
|
if !bp.iseq
|
1745
1757
|
bp.try_activate iseq
|
1746
1758
|
elsif reloaded
|
1747
1759
|
@bps.delete bp.key # to allow duplicate
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1760
|
+
|
1761
|
+
# When we delete a breakpoint from the @bps hash, we also need to deactivate it or else its tracepoint event
|
1762
|
+
# will continue to be enabled and we'll suspend on ghost breakpoints
|
1763
|
+
bp.delete
|
1764
|
+
|
1765
|
+
nbp = LineBreakpoint.copy(bp, iseq)
|
1766
|
+
add_bp nbp
|
1751
1767
|
end
|
1752
1768
|
end
|
1753
1769
|
else # !file_path => file_path is not existing
|
@@ -1993,6 +2009,13 @@ module DEBUGGER__
|
|
1993
2009
|
def after_fork_parent
|
1994
2010
|
@ui.after_fork_parent
|
1995
2011
|
end
|
2012
|
+
|
2013
|
+
# experimental API
|
2014
|
+
def extend_feature session: nil, thread_client: nil, ui: nil
|
2015
|
+
Session.include session if session
|
2016
|
+
ThreadClient.include thread_client if thread_client
|
2017
|
+
@ui.extend ui if ui
|
2018
|
+
end
|
1996
2019
|
end
|
1997
2020
|
|
1998
2021
|
class ProcessGroup
|
@@ -2167,6 +2190,7 @@ module DEBUGGER__
|
|
2167
2190
|
case loc.absolute_path
|
2168
2191
|
when dir_prefix
|
2169
2192
|
when %r{rubygems/core_ext/kernel_require\.rb}
|
2193
|
+
when %r{bundled_gems\.rb}
|
2170
2194
|
else
|
2171
2195
|
return loc if loc.absolute_path
|
2172
2196
|
end
|
@@ -2517,7 +2541,17 @@ module DEBUGGER__
|
|
2517
2541
|
|
2518
2542
|
module TrapInterceptor
|
2519
2543
|
def trap sig, *command, &command_proc
|
2520
|
-
|
2544
|
+
sym =
|
2545
|
+
case sig
|
2546
|
+
when String
|
2547
|
+
sig.to_sym
|
2548
|
+
when Integer
|
2549
|
+
Signal.signame(sig)&.to_sym
|
2550
|
+
else
|
2551
|
+
sig
|
2552
|
+
end
|
2553
|
+
|
2554
|
+
case sym
|
2521
2555
|
when :INT, :SIGINT
|
2522
2556
|
if defined?(SESSION) && SESSION.active? && SESSION.intercept_trap_sigint?
|
2523
2557
|
return SESSION.save_int_trap(command.empty? ? command_proc : command.first)
|