debug 1.7.2 → 1.9.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/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)
|