debug 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +124 -0
- data/Gemfile +1 -0
- data/README.md +16 -16
- data/Rakefile +5 -5
- data/debug.gemspec +6 -4
- data/ext/debug/debug.c +84 -0
- data/ext/debug/extconf.rb +11 -0
- data/lib/debug/breakpoint.rb +24 -35
- data/lib/debug/client.rb +9 -3
- data/lib/debug/console.rb +34 -13
- data/lib/debug/frame_info.rb +4 -5
- data/lib/debug/local.rb +1 -1
- data/lib/debug/server.rb +65 -27
- data/lib/debug/server_cdp.rb +369 -148
- data/lib/debug/server_dap.rb +72 -75
- data/lib/debug/session.rb +225 -114
- data/lib/debug/source_repository.rb +91 -51
- data/lib/debug/thread_client.rb +94 -42
- data/lib/debug/tracer.rb +3 -9
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +6 -6
- metadata +4 -13
- 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/session.rb
CHANGED
@@ -7,7 +7,7 @@ return if ENV['RUBY_DEBUG_ENABLE'] == '0'
|
|
7
7
|
if $0.end_with?('bin/bundle') && ARGV.first == 'exec'
|
8
8
|
trace_var(:$0) do |file|
|
9
9
|
trace_var(:$0, nil)
|
10
|
-
if /-r (#{__dir__}\S+)/ =~ ENV['RUBYOPT']
|
10
|
+
if /-r (#{Regexp.escape(__dir__)}\S+)/ =~ ENV['RUBYOPT']
|
11
11
|
lib = $1
|
12
12
|
$LOADED_FEATURES.delete_if{|path| path.start_with?(__dir__)}
|
13
13
|
ENV['RUBY_DEBUG_INITIAL_SUSPEND_PATH'] = file
|
@@ -31,7 +31,7 @@ $LOADED_FEATURES << 'debug.rb'
|
|
31
31
|
$LOADED_FEATURES << File.expand_path(File.join(__dir__, '..', 'debug.rb'))
|
32
32
|
require 'debug' # invalidate the $LOADED_FEATURE cache
|
33
33
|
|
34
|
-
require 'json' if ENV['
|
34
|
+
require 'json' if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal'
|
35
35
|
|
36
36
|
class RubyVM::InstructionSequence
|
37
37
|
def traceable_lines_norec lines
|
@@ -56,23 +56,22 @@ class RubyVM::InstructionSequence
|
|
56
56
|
|
57
57
|
def type
|
58
58
|
self.to_a[9]
|
59
|
-
end
|
60
|
-
|
61
|
-
def argc
|
62
|
-
self.to_a[4][:arg_size]
|
63
|
-
end
|
59
|
+
end unless method_defined?(:type)
|
64
60
|
|
65
|
-
def
|
66
|
-
self.to_a
|
67
|
-
|
61
|
+
def parameters_symbols
|
62
|
+
ary = self.to_a
|
63
|
+
argc = ary[4][:arg_size]
|
64
|
+
locals = ary.to_a[10]
|
65
|
+
locals[0...argc]
|
66
|
+
end unless method_defined?(:parameters_symbols)
|
68
67
|
|
69
68
|
def last_line
|
70
69
|
self.to_a[4][:code_location][2]
|
71
|
-
end
|
70
|
+
end unless method_defined?(:last_line)
|
72
71
|
|
73
72
|
def first_line
|
74
73
|
self.to_a[4][:code_location][0]
|
75
|
-
end
|
74
|
+
end unless method_defined?(:first_line)
|
76
75
|
end
|
77
76
|
|
78
77
|
module DEBUGGER__
|
@@ -82,8 +81,10 @@ module DEBUGGER__
|
|
82
81
|
class Session
|
83
82
|
attr_reader :intercepted_sigint_cmd, :process_group
|
84
83
|
|
85
|
-
|
86
|
-
|
84
|
+
include Color
|
85
|
+
|
86
|
+
def initialize
|
87
|
+
@ui = nil
|
87
88
|
@sr = SourceRepository.new
|
88
89
|
@bps = {} # bp.key => bp
|
89
90
|
# [file, line] => LineBreakpoint
|
@@ -104,13 +105,13 @@ module DEBUGGER__
|
|
104
105
|
@intercept_trap_sigint = false
|
105
106
|
@intercepted_sigint_cmd = 'DEFAULT'
|
106
107
|
@process_group = ProcessGroup.new
|
107
|
-
@
|
108
|
+
@subsession_stack = []
|
108
109
|
|
109
110
|
@frame_map = {} # for DAP: {id => [threadId, frame_depth]} and CDP: {id => frame_depth}
|
110
111
|
@var_map = {1 => [:globals], } # {id => ...} for DAP
|
111
112
|
@src_map = {} # {id => src}
|
112
113
|
|
113
|
-
@
|
114
|
+
@scr_id_map = {} # for CDP
|
114
115
|
@obj_map = {} # { object_id => ... } for CDP
|
115
116
|
|
116
117
|
@tp_thread_begin = nil
|
@@ -120,9 +121,6 @@ module DEBUGGER__
|
|
120
121
|
@tp_load_script.enable
|
121
122
|
|
122
123
|
@thread_stopper = thread_stopper
|
123
|
-
|
124
|
-
activate
|
125
|
-
|
126
124
|
self.postmortem = CONFIG[:postmortem]
|
127
125
|
end
|
128
126
|
|
@@ -134,15 +132,13 @@ module DEBUGGER__
|
|
134
132
|
@bps.has_key? [file, line]
|
135
133
|
end
|
136
134
|
|
137
|
-
def activate on_fork: false
|
135
|
+
def activate ui = nil, on_fork: false
|
136
|
+
@ui = ui if ui
|
137
|
+
|
138
138
|
@tp_thread_begin&.disable
|
139
139
|
@tp_thread_begin = nil
|
140
140
|
|
141
|
-
|
142
|
-
@ui.activate self, on_fork: true
|
143
|
-
else
|
144
|
-
@ui.activate self, on_fork: false
|
145
|
-
end
|
141
|
+
@ui.activate self, on_fork: on_fork
|
146
142
|
|
147
143
|
q = Queue.new
|
148
144
|
@session_server = Thread.new do
|
@@ -215,6 +211,7 @@ module DEBUGGER__
|
|
215
211
|
q << true
|
216
212
|
|
217
213
|
when :init
|
214
|
+
enter_subsession
|
218
215
|
wait_command_loop tc
|
219
216
|
|
220
217
|
when :load
|
@@ -257,7 +254,7 @@ module DEBUGGER__
|
|
257
254
|
end
|
258
255
|
|
259
256
|
when :result
|
260
|
-
raise "[BUG] not in subsession"
|
257
|
+
raise "[BUG] not in subsession" if @subsession_stack.empty?
|
261
258
|
|
262
259
|
case ev_args.first
|
263
260
|
when :try_display
|
@@ -369,7 +366,7 @@ module DEBUGGER__
|
|
369
366
|
@ui.puts "(rdbg:#{@preset_command.source}) #{line}"
|
370
367
|
end
|
371
368
|
else
|
372
|
-
@ui.puts "INTERNAL_INFO: #{JSON.generate(@internal_info)}" if ENV['
|
369
|
+
@ui.puts "INTERNAL_INFO: #{JSON.generate(@internal_info)}" if ENV['RUBY_DEBUG_TEST_UI'] == 'terminal'
|
373
370
|
line = @ui.readline prompt
|
374
371
|
end
|
375
372
|
|
@@ -510,8 +507,8 @@ module DEBUGGER__
|
|
510
507
|
# * break and run `<command>` before stopping.
|
511
508
|
# * `b[reak] ... do: <command>`
|
512
509
|
# * break and run `<command>`, and continue.
|
513
|
-
# * `b[reak] ... path: <
|
514
|
-
# * break if the
|
510
|
+
# * `b[reak] ... path: <path>`
|
511
|
+
# * break if the path matches to `<path>`. `<path>` can be a regexp with `/regexp/`.
|
515
512
|
# * `b[reak] if: <expr>`
|
516
513
|
# * break if: `<expr>` is true at any lines.
|
517
514
|
# * Note that this feature is super slow.
|
@@ -566,8 +563,8 @@ module DEBUGGER__
|
|
566
563
|
# * runs `<command>` before stopping.
|
567
564
|
# * `catch ... do: <command>`
|
568
565
|
# * stops and run `<command>`, and continue.
|
569
|
-
# * `catch ... path: <
|
570
|
-
# * stops if the exception is raised from a path
|
566
|
+
# * `catch ... path: <path>`
|
567
|
+
# * stops if the exception is raised from a `<path>`. `<path>` can be a regexp with `/regexp/`.
|
571
568
|
when 'catch'
|
572
569
|
check_postmortem
|
573
570
|
|
@@ -588,8 +585,8 @@ module DEBUGGER__
|
|
588
585
|
# * runs `<command>` before stopping.
|
589
586
|
# * `watch ... do: <command>`
|
590
587
|
# * stops and run `<command>`, and continue.
|
591
|
-
# * `watch ... path: <
|
592
|
-
# * stops if the
|
588
|
+
# * `watch ... path: <path>`
|
589
|
+
# * stops if the path matches `<path>`. `<path>` can be a regexp with `/regexp/`.
|
593
590
|
when 'wat', 'watch'
|
594
591
|
check_postmortem
|
595
592
|
|
@@ -699,8 +696,8 @@ module DEBUGGER__
|
|
699
696
|
# * Show information about accessible constants except toplevel constants.
|
700
697
|
# * `i[nfo] g[lobal[s]]`
|
701
698
|
# * Show information about global variables
|
702
|
-
# * `i[nfo] ...
|
703
|
-
# * Filter the output with
|
699
|
+
# * `i[nfo] ... /regexp/`
|
700
|
+
# * Filter the output with `/regexp/`.
|
704
701
|
# * `i[nfo] th[read[s]]`
|
705
702
|
# * Show all threads (same as `th[read]`).
|
706
703
|
when 'i', 'info'
|
@@ -834,8 +831,8 @@ module DEBUGGER__
|
|
834
831
|
# * Add an exception tracer. It indicates raising exceptions.
|
835
832
|
# * `trace object <expr>`
|
836
833
|
# * Add an object tracer. It indicates that an object by `<expr>` is passed as a parameter or a receiver on method call.
|
837
|
-
# * `trace ...
|
838
|
-
# * Indicates only matched events to
|
834
|
+
# * `trace ... /regexp/`
|
835
|
+
# * Indicates only matched events to `/regexp/`.
|
839
836
|
# * `trace ... into: <file>`
|
840
837
|
# * Save trace information into: `<file>`.
|
841
838
|
# * `trace off <num>`
|
@@ -978,7 +975,7 @@ module DEBUGGER__
|
|
978
975
|
when 'open'
|
979
976
|
case arg&.downcase
|
980
977
|
when '', nil
|
981
|
-
|
978
|
+
repl_open
|
982
979
|
when 'vscode'
|
983
980
|
repl_open_vscode
|
984
981
|
when /\A(.+):(\d+)\z/
|
@@ -1003,11 +1000,7 @@ module DEBUGGER__
|
|
1003
1000
|
# * `h[elp] <command>`
|
1004
1001
|
# * Show help for the given command.
|
1005
1002
|
when 'h', 'help', '?'
|
1006
|
-
|
1007
|
-
show_help arg
|
1008
|
-
else
|
1009
|
-
@ui.puts DEBUGGER__.help
|
1010
|
-
end
|
1003
|
+
show_help arg
|
1011
1004
|
return :retry
|
1012
1005
|
|
1013
1006
|
### END
|
@@ -1055,14 +1048,14 @@ module DEBUGGER__
|
|
1055
1048
|
repl_open_setup
|
1056
1049
|
end
|
1057
1050
|
|
1058
|
-
def
|
1059
|
-
DEBUGGER__.
|
1051
|
+
def repl_open
|
1052
|
+
DEBUGGER__.open nonstop: true
|
1060
1053
|
repl_open_setup
|
1061
1054
|
end
|
1062
1055
|
|
1063
1056
|
def repl_open_vscode
|
1064
1057
|
CONFIG[:open_frontend] = 'vscode'
|
1065
|
-
|
1058
|
+
repl_open
|
1066
1059
|
end
|
1067
1060
|
|
1068
1061
|
def step_command type, arg
|
@@ -1159,16 +1152,50 @@ module DEBUGGER__
|
|
1159
1152
|
end
|
1160
1153
|
end
|
1161
1154
|
|
1162
|
-
def show_help arg
|
1163
|
-
DEBUGGER__.
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1155
|
+
def show_help arg = nil
|
1156
|
+
instructions = (DEBUGGER__.commands.keys + DEBUGGER__.commands.values).uniq
|
1157
|
+
print_instructions = proc do |desc|
|
1158
|
+
desc.split("\n").each do |line|
|
1159
|
+
next if line.start_with?(" ") # workaround for step back
|
1160
|
+
formatted_line = line.gsub(/[\[\]\*]/, "").strip
|
1161
|
+
instructions.each do |inst|
|
1162
|
+
if formatted_line.start_with?("`#{inst}")
|
1163
|
+
desc.sub!(line, colorize(line, [:CYAN, :BOLD]))
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
@ui.puts desc
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
print_category = proc do |cat|
|
1171
|
+
@ui.puts "\n"
|
1172
|
+
@ui.puts colorize("### #{cat}", [:GREEN, :BOLD])
|
1173
|
+
@ui.puts "\n"
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
DEBUGGER__.helps.each { |cat, cs|
|
1177
|
+
# categories
|
1178
|
+
if arg.nil?
|
1179
|
+
print_category.call(cat)
|
1180
|
+
else
|
1181
|
+
cs.each { |ws, _|
|
1182
|
+
if ws.include?(arg)
|
1183
|
+
print_category.call(cat)
|
1184
|
+
break
|
1185
|
+
end
|
1186
|
+
}
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
# instructions
|
1190
|
+
cs.each { |ws, desc|
|
1191
|
+
if arg.nil? || ws.include?(arg)
|
1192
|
+
print_instructions.call(desc.dup)
|
1193
|
+
return if arg
|
1168
1194
|
end
|
1169
1195
|
}
|
1170
1196
|
}
|
1171
|
-
|
1197
|
+
|
1198
|
+
@ui.puts "not found: #{arg}" if arg
|
1172
1199
|
end
|
1173
1200
|
|
1174
1201
|
def ask msg, default = 'Y'
|
@@ -1272,14 +1299,20 @@ module DEBUGGER__
|
|
1272
1299
|
end
|
1273
1300
|
}
|
1274
1301
|
expr.default_proc = nil
|
1275
|
-
expr.transform_values{|v| v.join(' ')}
|
1302
|
+
expr = expr.transform_values{|v| v.join(' ')}
|
1303
|
+
|
1304
|
+
if (path = expr[:path]) && path =~ /\A\/(.*)\/\z/
|
1305
|
+
expr[:path] = Regexp.compile($1)
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
expr
|
1276
1309
|
end
|
1277
1310
|
|
1278
1311
|
def repl_add_breakpoint arg
|
1279
1312
|
expr = parse_break arg.strip
|
1280
1313
|
cond = expr[:if]
|
1281
1314
|
cmd = ['break', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
1282
|
-
path =
|
1315
|
+
path = expr[:path]
|
1283
1316
|
|
1284
1317
|
case expr[:sig]
|
1285
1318
|
when /\A(\d+)\z/
|
@@ -1290,7 +1323,7 @@ module DEBUGGER__
|
|
1290
1323
|
@tc << [:breakpoint, :method, $1, $2, $3, cond, cmd, path]
|
1291
1324
|
return :noretry
|
1292
1325
|
when nil
|
1293
|
-
add_check_breakpoint cond, path
|
1326
|
+
add_check_breakpoint cond, path, cmd
|
1294
1327
|
else
|
1295
1328
|
@ui.puts "Unknown breakpoint format: #{arg}"
|
1296
1329
|
@ui.puts
|
@@ -1302,7 +1335,7 @@ module DEBUGGER__
|
|
1302
1335
|
expr = parse_break arg.strip
|
1303
1336
|
cond = expr[:if]
|
1304
1337
|
cmd = ['catch', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
1305
|
-
path =
|
1338
|
+
path = expr[:path]
|
1306
1339
|
|
1307
1340
|
bp = CatchBreakpoint.new(expr[:sig], cond: cond, command: cmd, path: path)
|
1308
1341
|
add_bp bp
|
@@ -1322,8 +1355,8 @@ module DEBUGGER__
|
|
1322
1355
|
add_bp bp
|
1323
1356
|
end
|
1324
1357
|
|
1325
|
-
def add_check_breakpoint
|
1326
|
-
bp = CheckBreakpoint.new(
|
1358
|
+
def add_check_breakpoint cond, path, command
|
1359
|
+
bp = CheckBreakpoint.new(cond: cond, path: path, command: command)
|
1327
1360
|
add_bp bp
|
1328
1361
|
end
|
1329
1362
|
|
@@ -1336,6 +1369,15 @@ module DEBUGGER__
|
|
1336
1369
|
@ui.puts e.message
|
1337
1370
|
end
|
1338
1371
|
|
1372
|
+
def clear_line_breakpoints path
|
1373
|
+
path = resolve_path(path)
|
1374
|
+
@bps.delete_if do |k, bp|
|
1375
|
+
if (Array === k) && DEBUGGER__.compare_path(k.first, path)
|
1376
|
+
bp.delete
|
1377
|
+
end
|
1378
|
+
end
|
1379
|
+
end
|
1380
|
+
|
1339
1381
|
def add_iseq_breakpoint iseq, **kw
|
1340
1382
|
bp = ISeqBreakpoint.new(iseq, [:line], **kw)
|
1341
1383
|
add_bp bp
|
@@ -1503,27 +1545,38 @@ module DEBUGGER__
|
|
1503
1545
|
end
|
1504
1546
|
|
1505
1547
|
private def enter_subsession
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1548
|
+
if !@subsession_stack.empty?
|
1549
|
+
DEBUGGER__.info "Enter subsession (nested #{@subsession_stack.size})"
|
1550
|
+
else
|
1551
|
+
DEBUGGER__.info "Enter subsession"
|
1552
|
+
stop_all_threads
|
1553
|
+
@process_group.lock
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
@subsession_stack << true
|
1511
1557
|
end
|
1512
1558
|
|
1513
1559
|
private def leave_subsession type
|
1514
|
-
|
1515
|
-
@
|
1516
|
-
|
1560
|
+
raise '[BUG] leave_subsession: not entered' if @subsession_stack.empty?
|
1561
|
+
@subsession_stack.pop
|
1562
|
+
|
1563
|
+
if @subsession_stack.empty?
|
1564
|
+
DEBUGGER__.info "Leave subsession"
|
1565
|
+
@process_group.unlock
|
1566
|
+
restart_all_threads
|
1567
|
+
else
|
1568
|
+
DEBUGGER__.info "Leave subsession (nested #{@subsession_stack.size})"
|
1569
|
+
end
|
1570
|
+
|
1517
1571
|
@tc << type if type
|
1518
1572
|
@tc = nil
|
1519
|
-
@subsession = false
|
1520
1573
|
rescue Exception => e
|
1521
|
-
STDERR.puts [e, e.backtrace].
|
1574
|
+
STDERR.puts PP.pp([e, e.backtrace], ''.dup)
|
1522
1575
|
raise
|
1523
1576
|
end
|
1524
1577
|
|
1525
1578
|
def in_subsession?
|
1526
|
-
|
1579
|
+
!@subsession_stack.empty?
|
1527
1580
|
end
|
1528
1581
|
|
1529
1582
|
## event
|
@@ -1537,7 +1590,7 @@ module DEBUGGER__
|
|
1537
1590
|
end
|
1538
1591
|
|
1539
1592
|
pending_line_breakpoints.each do |_key, bp|
|
1540
|
-
if bp.path
|
1593
|
+
if DEBUGGER__.compare_path(bp.path, (iseq.absolute_path || iseq.path))
|
1541
1594
|
bp.try_activate
|
1542
1595
|
end
|
1543
1596
|
end
|
@@ -1860,6 +1913,9 @@ module DEBUGGER__
|
|
1860
1913
|
puts "\nStop by #{args.first}"
|
1861
1914
|
end
|
1862
1915
|
end
|
1916
|
+
|
1917
|
+
def flush
|
1918
|
+
end
|
1863
1919
|
end
|
1864
1920
|
|
1865
1921
|
# manual configuration methods
|
@@ -1876,7 +1932,7 @@ module DEBUGGER__
|
|
1876
1932
|
# nil for -r
|
1877
1933
|
def self.require_location
|
1878
1934
|
locs = caller_locations
|
1879
|
-
dir_prefix = /#{__dir__}/
|
1935
|
+
dir_prefix = /#{Regexp.escape(__dir__)}/
|
1880
1936
|
|
1881
1937
|
locs.each do |loc|
|
1882
1938
|
case loc.absolute_path
|
@@ -1896,7 +1952,7 @@ module DEBUGGER__
|
|
1896
1952
|
|
1897
1953
|
unless defined? SESSION
|
1898
1954
|
require_relative 'local'
|
1899
|
-
initialize_session UI_LocalConsole.new
|
1955
|
+
initialize_session{ UI_LocalConsole.new }
|
1900
1956
|
end
|
1901
1957
|
|
1902
1958
|
setup_initial_suspend unless nonstop
|
@@ -1904,8 +1960,9 @@ module DEBUGGER__
|
|
1904
1960
|
|
1905
1961
|
def self.open host: nil, port: CONFIG[:port], sock_path: nil, sock_dir: nil, nonstop: false, **kw
|
1906
1962
|
CONFIG.set_config(**kw)
|
1963
|
+
require_relative 'server'
|
1907
1964
|
|
1908
|
-
if port || CONFIG[:open_frontend] == 'chrome'
|
1965
|
+
if port || CONFIG[:open_frontend] == 'chrome' || (!::Addrinfo.respond_to?(:unix))
|
1909
1966
|
open_tcp host: host, port: (port || 0), nonstop: nonstop
|
1910
1967
|
else
|
1911
1968
|
open_unix sock_path: sock_path, sock_dir: sock_dir, nonstop: nonstop
|
@@ -1919,7 +1976,7 @@ module DEBUGGER__
|
|
1919
1976
|
if defined? SESSION
|
1920
1977
|
SESSION.reset_ui UI_TcpServer.new(host: host, port: port)
|
1921
1978
|
else
|
1922
|
-
initialize_session UI_TcpServer.new(host: host, port: port)
|
1979
|
+
initialize_session{ UI_TcpServer.new(host: host, port: port) }
|
1923
1980
|
end
|
1924
1981
|
|
1925
1982
|
setup_initial_suspend unless nonstop
|
@@ -1932,7 +1989,7 @@ module DEBUGGER__
|
|
1932
1989
|
if defined? SESSION
|
1933
1990
|
SESSION.reset_ui UI_UnixDomainServer.new(sock_dir: sock_dir, sock_path: sock_path)
|
1934
1991
|
else
|
1935
|
-
initialize_session UI_UnixDomainServer.new(sock_dir: sock_dir, sock_path: sock_path)
|
1992
|
+
initialize_session{ UI_UnixDomainServer.new(sock_dir: sock_dir, sock_path: sock_path) }
|
1936
1993
|
end
|
1937
1994
|
|
1938
1995
|
setup_initial_suspend unless nonstop
|
@@ -1959,9 +2016,10 @@ module DEBUGGER__
|
|
1959
2016
|
end
|
1960
2017
|
|
1961
2018
|
class << self
|
1962
|
-
define_method :initialize_session do |
|
2019
|
+
define_method :initialize_session do |&init_ui|
|
1963
2020
|
DEBUGGER__.info "Session start (pid: #{Process.pid})"
|
1964
|
-
::DEBUGGER__.const_set(:SESSION, Session.new
|
2021
|
+
::DEBUGGER__.const_set(:SESSION, Session.new)
|
2022
|
+
SESSION.activate init_ui.call
|
1965
2023
|
load_rc
|
1966
2024
|
end
|
1967
2025
|
end
|
@@ -2062,10 +2120,64 @@ module DEBUGGER__
|
|
2062
2120
|
yield
|
2063
2121
|
end
|
2064
2122
|
|
2123
|
+
if File.identical?(__FILE__.upcase, __FILE__.downcase)
|
2124
|
+
# For case insensitive file system (like Windows)
|
2125
|
+
# Note that this check is not enough because case sensitive/insensitive is
|
2126
|
+
# depend on the file system. So this check is only roughly estimation.
|
2127
|
+
|
2128
|
+
def self.compare_path(a, b)
|
2129
|
+
a.downcase == b.downcase
|
2130
|
+
end
|
2131
|
+
else
|
2132
|
+
def self.compare_path(a, b)
|
2133
|
+
a == b
|
2134
|
+
end
|
2135
|
+
end
|
2136
|
+
|
2065
2137
|
module ForkInterceptor
|
2066
|
-
|
2067
|
-
|
2138
|
+
if Process.respond_to? :_fork
|
2139
|
+
def _fork
|
2140
|
+
return yield unless defined?(SESSION) && SESSION.active?
|
2141
|
+
|
2142
|
+
parent_hook, child_hook = __fork_setup_for_debugger
|
2143
|
+
|
2144
|
+
super.tap do |pid|
|
2145
|
+
if pid != 0
|
2146
|
+
# after fork: parent
|
2147
|
+
parent_hook.call pid
|
2148
|
+
else
|
2149
|
+
# after fork: child
|
2150
|
+
child_hook.call
|
2151
|
+
end
|
2152
|
+
end
|
2153
|
+
end
|
2154
|
+
else
|
2155
|
+
def fork(&given_block)
|
2156
|
+
return yield unless defined?(SESSION) && SESSION.active?
|
2157
|
+
parent_hook, child_hook = __fork_setup_for_debugger
|
2158
|
+
|
2159
|
+
if given_block
|
2160
|
+
new_block = proc {
|
2161
|
+
# after fork: child
|
2162
|
+
child_hook.call
|
2163
|
+
given_block.call
|
2164
|
+
}
|
2165
|
+
super(&new_block).tap{|pid| parent_hook.call(pid)}
|
2166
|
+
else
|
2167
|
+
super.tap do |pid|
|
2168
|
+
if pid
|
2169
|
+
# after fork: parent
|
2170
|
+
parent_hook.call pid
|
2171
|
+
else
|
2172
|
+
# after fork: child
|
2173
|
+
child_hook.call
|
2174
|
+
end
|
2175
|
+
end
|
2176
|
+
end
|
2177
|
+
end
|
2178
|
+
end
|
2068
2179
|
|
2180
|
+
private def __fork_setup_for_debugger
|
2069
2181
|
unless fork_mode = CONFIG[:fork_mode]
|
2070
2182
|
if CONFIG[:parent_on_fork]
|
2071
2183
|
fork_mode = :parent
|
@@ -2112,26 +2224,7 @@ module DEBUGGER__
|
|
2112
2224
|
}
|
2113
2225
|
end
|
2114
2226
|
|
2115
|
-
|
2116
|
-
new_block = proc {
|
2117
|
-
# after fork: child
|
2118
|
-
child_hook.call
|
2119
|
-
given_block.call
|
2120
|
-
}
|
2121
|
-
pid = super(&new_block)
|
2122
|
-
parent_hook.call(pid)
|
2123
|
-
pid
|
2124
|
-
else
|
2125
|
-
if pid = super
|
2126
|
-
# after fork: parent
|
2127
|
-
parent_hook.call pid
|
2128
|
-
else
|
2129
|
-
# after fork: child
|
2130
|
-
child_hook.call
|
2131
|
-
end
|
2132
|
-
|
2133
|
-
pid
|
2134
|
-
end
|
2227
|
+
return parent_hook, child_hook
|
2135
2228
|
end
|
2136
2229
|
end
|
2137
2230
|
|
@@ -2148,28 +2241,46 @@ module DEBUGGER__
|
|
2148
2241
|
end
|
2149
2242
|
end
|
2150
2243
|
|
2151
|
-
if
|
2244
|
+
if Process.respond_to? :_fork
|
2245
|
+
module ::Process
|
2246
|
+
class << self
|
2247
|
+
prepend ForkInterceptor
|
2248
|
+
end
|
2249
|
+
end
|
2250
|
+
|
2251
|
+
# trap
|
2152
2252
|
module ::Kernel
|
2153
|
-
prepend ForkInterceptor
|
2154
2253
|
prepend TrapInterceptor
|
2155
2254
|
end
|
2255
|
+
module ::Signal
|
2256
|
+
class << self
|
2257
|
+
prepend TrapInterceptor
|
2258
|
+
end
|
2259
|
+
end
|
2156
2260
|
else
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2261
|
+
if RUBY_VERSION >= '3.0.0'
|
2262
|
+
module ::Kernel
|
2263
|
+
prepend ForkInterceptor
|
2264
|
+
prepend TrapInterceptor
|
2265
|
+
end
|
2266
|
+
else
|
2267
|
+
class ::Object
|
2268
|
+
include ForkInterceptor
|
2269
|
+
include TrapInterceptor
|
2270
|
+
end
|
2160
2271
|
end
|
2161
|
-
end
|
2162
2272
|
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
|
2273
|
+
module ::Kernel
|
2274
|
+
class << self
|
2275
|
+
prepend ForkInterceptor
|
2276
|
+
prepend TrapInterceptor
|
2277
|
+
end
|
2167
2278
|
end
|
2168
|
-
end
|
2169
2279
|
|
2170
|
-
|
2171
|
-
|
2172
|
-
|
2280
|
+
module ::Process
|
2281
|
+
class << self
|
2282
|
+
prepend ForkInterceptor
|
2283
|
+
end
|
2173
2284
|
end
|
2174
2285
|
end
|
2175
2286
|
|