debug 1.3.1 → 1.4.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/.github/pull_request_template.md +9 -0
- data/CONTRIBUTING.md +43 -12
- data/README.md +38 -11
- data/bin/gentest +12 -4
- data/ext/debug/debug.c +5 -2
- data/lib/debug/breakpoint.rb +61 -11
- data/lib/debug/client.rb +57 -16
- data/lib/debug/color.rb +30 -20
- data/lib/debug/config.rb +6 -3
- data/lib/debug/console.rb +17 -3
- data/lib/debug/frame_info.rb +11 -16
- data/lib/debug/prelude.rb +2 -2
- data/lib/debug/server.rb +47 -77
- data/lib/debug/server_cdp.rb +605 -94
- data/lib/debug/server_dap.rb +256 -57
- data/lib/debug/session.rb +146 -54
- data/lib/debug/source_repository.rb +4 -6
- data/lib/debug/thread_client.rb +67 -48
- data/lib/debug/tracer.rb +1 -1
- data/lib/debug/version.rb +1 -1
- data/misc/README.md.erb +16 -8
- metadata +3 -2
data/lib/debug/session.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
return if ENV['RUBY_DEBUG_ENABLE'] == '0'
|
|
4
|
+
|
|
3
5
|
# skip to load debugger for bundle exec
|
|
4
6
|
|
|
5
7
|
if $0.end_with?('bin/bundle') && ARGV.first == 'exec'
|
|
@@ -91,7 +93,7 @@ module DEBUGGER__
|
|
|
91
93
|
# [:check, expr] => CheckBreakpoint
|
|
92
94
|
#
|
|
93
95
|
@tracers = {}
|
|
94
|
-
@th_clients =
|
|
96
|
+
@th_clients = {} # {Thread => ThreadClient}
|
|
95
97
|
@q_evt = Queue.new
|
|
96
98
|
@displays = []
|
|
97
99
|
@tc = nil
|
|
@@ -99,17 +101,17 @@ module DEBUGGER__
|
|
|
99
101
|
@preset_command = nil
|
|
100
102
|
@postmortem_hook = nil
|
|
101
103
|
@postmortem = false
|
|
102
|
-
@thread_stopper = nil
|
|
103
104
|
@intercept_trap_sigint = false
|
|
104
105
|
@intercepted_sigint_cmd = 'DEFAULT'
|
|
105
106
|
@process_group = ProcessGroup.new
|
|
106
107
|
@subsession = nil
|
|
107
108
|
|
|
108
|
-
@frame_map = {} # {id => [threadId, frame_depth]}
|
|
109
|
+
@frame_map = {} # for DAP: {id => [threadId, frame_depth]} and CDP: {id => frame_depth}
|
|
109
110
|
@var_map = {1 => [:globals], } # {id => ...} for DAP
|
|
110
111
|
@src_map = {} # {id => src}
|
|
111
112
|
|
|
112
113
|
@script_paths = [File.absolute_path($0)] # for CDP
|
|
114
|
+
@obj_map = {} # { object_id => ... } for CDP
|
|
113
115
|
|
|
114
116
|
@tp_thread_begin = nil
|
|
115
117
|
@tp_load_script = TracePoint.new(:script_compiled){|tp|
|
|
@@ -117,6 +119,8 @@ module DEBUGGER__
|
|
|
117
119
|
}
|
|
118
120
|
@tp_load_script.enable
|
|
119
121
|
|
|
122
|
+
@thread_stopper = thread_stopper
|
|
123
|
+
|
|
120
124
|
activate
|
|
121
125
|
|
|
122
126
|
self.postmortem = CONFIG[:postmortem]
|
|
@@ -147,15 +151,15 @@ module DEBUGGER__
|
|
|
147
151
|
|
|
148
152
|
# Thread management
|
|
149
153
|
setup_threads
|
|
150
|
-
thc =
|
|
151
|
-
thc.
|
|
154
|
+
thc = get_thread_client Thread.current
|
|
155
|
+
thc.mark_as_management
|
|
152
156
|
|
|
153
|
-
if @ui.respond_to?(:reader_thread) && thc =
|
|
154
|
-
thc.
|
|
157
|
+
if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread)
|
|
158
|
+
thc.mark_as_management
|
|
155
159
|
end
|
|
156
160
|
|
|
157
161
|
@tp_thread_begin = TracePoint.new(:thread_begin) do |tp|
|
|
158
|
-
|
|
162
|
+
get_thread_client
|
|
159
163
|
end
|
|
160
164
|
@tp_thread_begin.enable
|
|
161
165
|
|
|
@@ -168,12 +172,12 @@ module DEBUGGER__
|
|
|
168
172
|
end
|
|
169
173
|
|
|
170
174
|
def deactivate
|
|
171
|
-
|
|
172
|
-
@thread_stopper.disable
|
|
175
|
+
get_thread_client.deactivate
|
|
176
|
+
@thread_stopper.disable
|
|
173
177
|
@tp_load_script.disable
|
|
174
178
|
@tp_thread_begin.disable
|
|
175
|
-
@bps.
|
|
176
|
-
@th_clients.
|
|
179
|
+
@bps.each_value{|bp| bp.disable}
|
|
180
|
+
@th_clients.each_value{|thc| thc.close}
|
|
177
181
|
@tracers.values.each{|t| t.disable}
|
|
178
182
|
@q_evt.close
|
|
179
183
|
@ui&.deactivate
|
|
@@ -233,12 +237,13 @@ module DEBUGGER__
|
|
|
233
237
|
case ev_args.first
|
|
234
238
|
when :breakpoint
|
|
235
239
|
bp, i = bp_index ev_args[1]
|
|
240
|
+
clean_bps unless bp
|
|
236
241
|
@ui.event :suspend_bp, i, bp, tc.id
|
|
237
242
|
when :trap
|
|
238
243
|
@ui.event :suspend_trap, sig = ev_args[1], tc.id
|
|
239
244
|
|
|
240
245
|
if sig == :SIGINT && (@intercepted_sigint_cmd.kind_of?(Proc) || @intercepted_sigint_cmd.kind_of?(String))
|
|
241
|
-
@ui.puts "#{@intercepted_sigint_cmd.inspect} is
|
|
246
|
+
@ui.puts "#{@intercepted_sigint_cmd.inspect} is registered as SIGINT handler."
|
|
242
247
|
@ui.puts "`sigint` command execute it."
|
|
243
248
|
end
|
|
244
249
|
else
|
|
@@ -418,10 +423,15 @@ module DEBUGGER__
|
|
|
418
423
|
# * `fin[ish]`
|
|
419
424
|
# * Finish this frame. Resume the program until the current frame is finished.
|
|
420
425
|
# * `fin[ish] <n>`
|
|
421
|
-
# * Finish frames
|
|
426
|
+
# * Finish `<n>`th frames.
|
|
422
427
|
when 'fin', 'finish'
|
|
423
428
|
cancel_auto_continue
|
|
424
429
|
check_postmortem
|
|
430
|
+
|
|
431
|
+
if arg&.to_i == 0
|
|
432
|
+
raise 'finish command with 0 does not make sense.'
|
|
433
|
+
end
|
|
434
|
+
|
|
425
435
|
step_command :finish, arg
|
|
426
436
|
|
|
427
437
|
# * `c[ontinue]`
|
|
@@ -447,7 +457,7 @@ module DEBUGGER__
|
|
|
447
457
|
leave_subsession nil
|
|
448
458
|
|
|
449
459
|
# * `kill`
|
|
450
|
-
# * Stop the debuggee process with `
|
|
460
|
+
# * Stop the debuggee process with `Kernel#exit!`.
|
|
451
461
|
when 'kill'
|
|
452
462
|
if ask 'Really kill?'
|
|
453
463
|
exit! (arg || 1).to_i
|
|
@@ -461,7 +471,7 @@ module DEBUGGER__
|
|
|
461
471
|
exit! (arg || 1).to_i
|
|
462
472
|
|
|
463
473
|
# * `sigint`
|
|
464
|
-
# * Execute SIGINT handler
|
|
474
|
+
# * Execute SIGINT handler registered by the debuggee.
|
|
465
475
|
# * Note that this command should be used just after stop by `SIGINT`.
|
|
466
476
|
when 'sigint'
|
|
467
477
|
begin
|
|
@@ -500,6 +510,8 @@ module DEBUGGER__
|
|
|
500
510
|
# * break and run `<command>` before stopping.
|
|
501
511
|
# * `b[reak] ... do: <command>`
|
|
502
512
|
# * break and run `<command>`, and continue.
|
|
513
|
+
# * `b[reak] ... path: <path_regexp>`
|
|
514
|
+
# * break if the triggering event's path matches <path_regexp>.
|
|
503
515
|
# * `b[reak] if: <expr>`
|
|
504
516
|
# * break if: `<expr>` is true at any lines.
|
|
505
517
|
# * Note that this feature is super slow.
|
|
@@ -526,7 +538,7 @@ module DEBUGGER__
|
|
|
526
538
|
require 'json'
|
|
527
539
|
|
|
528
540
|
h = Hash.new{|h, k| h[k] = []}
|
|
529
|
-
@bps.
|
|
541
|
+
@bps.each_value{|bp|
|
|
530
542
|
if LineBreakpoint === bp
|
|
531
543
|
h[bp.path] << {lnum: bp.line}
|
|
532
544
|
end
|
|
@@ -548,6 +560,14 @@ module DEBUGGER__
|
|
|
548
560
|
|
|
549
561
|
# * `catch <Error>`
|
|
550
562
|
# * Set breakpoint on raising `<Error>`.
|
|
563
|
+
# * `catch ... if: <expr>`
|
|
564
|
+
# * stops only if `<expr>` is true as well.
|
|
565
|
+
# * `catch ... pre: <command>`
|
|
566
|
+
# * runs `<command>` before stopping.
|
|
567
|
+
# * `catch ... do: <command>`
|
|
568
|
+
# * stops and run `<command>`, and continue.
|
|
569
|
+
# * `catch ... path: <path_regexp>`
|
|
570
|
+
# * stops if the exception is raised from a path that matches <path_regexp>.
|
|
551
571
|
when 'catch'
|
|
552
572
|
check_postmortem
|
|
553
573
|
|
|
@@ -562,11 +582,19 @@ module DEBUGGER__
|
|
|
562
582
|
# * `watch @ivar`
|
|
563
583
|
# * Stop the execution when the result of current scope's `@ivar` is changed.
|
|
564
584
|
# * Note that this feature is super slow.
|
|
585
|
+
# * `watch ... if: <expr>`
|
|
586
|
+
# * stops only if `<expr>` is true as well.
|
|
587
|
+
# * `watch ... pre: <command>`
|
|
588
|
+
# * runs `<command>` before stopping.
|
|
589
|
+
# * `watch ... do: <command>`
|
|
590
|
+
# * stops and run `<command>`, and continue.
|
|
591
|
+
# * `watch ... path: <path_regexp>`
|
|
592
|
+
# * stops if the triggering event's path matches <path_regexp>.
|
|
565
593
|
when 'wat', 'watch'
|
|
566
594
|
check_postmortem
|
|
567
595
|
|
|
568
596
|
if arg && arg.match?(/\A@\w+/)
|
|
569
|
-
|
|
597
|
+
repl_add_watch_breakpoint(arg)
|
|
570
598
|
else
|
|
571
599
|
show_bps
|
|
572
600
|
return :retry
|
|
@@ -902,7 +930,7 @@ module DEBUGGER__
|
|
|
902
930
|
when nil, 'list', 'l'
|
|
903
931
|
thread_list
|
|
904
932
|
when /(\d+)/
|
|
905
|
-
|
|
933
|
+
switch_thread $1.to_i
|
|
906
934
|
else
|
|
907
935
|
@ui.puts "unknown thread command: #{arg}"
|
|
908
936
|
end
|
|
@@ -1016,8 +1044,8 @@ module DEBUGGER__
|
|
|
1016
1044
|
def repl_open_setup
|
|
1017
1045
|
@tp_thread_begin.disable
|
|
1018
1046
|
@ui.activate self
|
|
1019
|
-
if @ui.respond_to?(:reader_thread) && thc =
|
|
1020
|
-
thc.
|
|
1047
|
+
if @ui.respond_to?(:reader_thread) && thc = get_thread_client(@ui.reader_thread)
|
|
1048
|
+
thc.mark_as_management
|
|
1021
1049
|
end
|
|
1022
1050
|
@tp_thread_begin.enable
|
|
1023
1051
|
end
|
|
@@ -1195,6 +1223,12 @@ module DEBUGGER__
|
|
|
1195
1223
|
}
|
|
1196
1224
|
end
|
|
1197
1225
|
|
|
1226
|
+
def clean_bps
|
|
1227
|
+
@bps.delete_if{|_k, bp|
|
|
1228
|
+
bp.deleted?
|
|
1229
|
+
}
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1198
1232
|
def add_bp bp
|
|
1199
1233
|
# don't repeat commands that add breakpoints
|
|
1200
1234
|
@repl_prev_line = nil
|
|
@@ -1225,7 +1259,7 @@ module DEBUGGER__
|
|
|
1225
1259
|
end
|
|
1226
1260
|
end
|
|
1227
1261
|
|
|
1228
|
-
BREAK_KEYWORDS = %w(if: do: pre:).freeze
|
|
1262
|
+
BREAK_KEYWORDS = %w(if: do: pre: path:).freeze
|
|
1229
1263
|
|
|
1230
1264
|
def parse_break arg
|
|
1231
1265
|
mode = :sig
|
|
@@ -1245,6 +1279,7 @@ module DEBUGGER__
|
|
|
1245
1279
|
expr = parse_break arg.strip
|
|
1246
1280
|
cond = expr[:if]
|
|
1247
1281
|
cmd = ['break', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
|
1282
|
+
path = Regexp.compile(expr[:path]) if expr[:path]
|
|
1248
1283
|
|
|
1249
1284
|
case expr[:sig]
|
|
1250
1285
|
when /\A(\d+)\z/
|
|
@@ -1252,10 +1287,10 @@ module DEBUGGER__
|
|
|
1252
1287
|
when /\A(.+)[:\s+](\d+)\z/
|
|
1253
1288
|
add_line_breakpoint $1, $2.to_i, cond: cond, command: cmd
|
|
1254
1289
|
when /\A(.+)([\.\#])(.+)\z/
|
|
1255
|
-
@tc << [:breakpoint, :method, $1, $2, $3, cond, cmd]
|
|
1290
|
+
@tc << [:breakpoint, :method, $1, $2, $3, cond, cmd, path]
|
|
1256
1291
|
return :noretry
|
|
1257
1292
|
when nil
|
|
1258
|
-
add_check_breakpoint cond
|
|
1293
|
+
add_check_breakpoint cond, path
|
|
1259
1294
|
else
|
|
1260
1295
|
@ui.puts "Unknown breakpoint format: #{arg}"
|
|
1261
1296
|
@ui.puts
|
|
@@ -1267,18 +1302,28 @@ module DEBUGGER__
|
|
|
1267
1302
|
expr = parse_break arg.strip
|
|
1268
1303
|
cond = expr[:if]
|
|
1269
1304
|
cmd = ['catch', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
|
1305
|
+
path = Regexp.compile(expr[:path]) if expr[:path]
|
|
1270
1306
|
|
|
1271
|
-
bp = CatchBreakpoint.new(expr[:sig], cond: cond, command: cmd)
|
|
1307
|
+
bp = CatchBreakpoint.new(expr[:sig], cond: cond, command: cmd, path: path)
|
|
1272
1308
|
add_bp bp
|
|
1273
1309
|
end
|
|
1274
1310
|
|
|
1311
|
+
def repl_add_watch_breakpoint arg
|
|
1312
|
+
expr = parse_break arg.strip
|
|
1313
|
+
cond = expr[:if]
|
|
1314
|
+
cmd = ['watch', expr[:pre], expr[:do]] if expr[:pre] || expr[:do]
|
|
1315
|
+
path = Regexp.compile(expr[:path]) if expr[:path]
|
|
1316
|
+
|
|
1317
|
+
@tc << [:breakpoint, :watch, expr[:sig], cond, cmd, path]
|
|
1318
|
+
end
|
|
1319
|
+
|
|
1275
1320
|
def add_catch_breakpoint pat
|
|
1276
1321
|
bp = CatchBreakpoint.new(pat)
|
|
1277
1322
|
add_bp bp
|
|
1278
1323
|
end
|
|
1279
1324
|
|
|
1280
|
-
def add_check_breakpoint expr
|
|
1281
|
-
bp = CheckBreakpoint.new(expr)
|
|
1325
|
+
def add_check_breakpoint expr, path
|
|
1326
|
+
bp = CheckBreakpoint.new(expr, path)
|
|
1282
1327
|
add_bp bp
|
|
1283
1328
|
end
|
|
1284
1329
|
|
|
@@ -1291,6 +1336,11 @@ module DEBUGGER__
|
|
|
1291
1336
|
@ui.puts e.message
|
|
1292
1337
|
end
|
|
1293
1338
|
|
|
1339
|
+
def add_iseq_breakpoint iseq, **kw
|
|
1340
|
+
bp = ISeqBreakpoint.new(iseq, [:line], **kw)
|
|
1341
|
+
add_bp bp
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1294
1344
|
# tracers
|
|
1295
1345
|
|
|
1296
1346
|
def add_tracer tracer
|
|
@@ -1344,7 +1394,7 @@ module DEBUGGER__
|
|
|
1344
1394
|
thcs
|
|
1345
1395
|
end
|
|
1346
1396
|
|
|
1347
|
-
def
|
|
1397
|
+
def switch_thread n
|
|
1348
1398
|
thcs, _unmanaged_ths = update_thread_list
|
|
1349
1399
|
|
|
1350
1400
|
if tc = thcs[n]
|
|
@@ -1358,14 +1408,14 @@ module DEBUGGER__
|
|
|
1358
1408
|
end
|
|
1359
1409
|
|
|
1360
1410
|
def setup_threads
|
|
1361
|
-
prev_clients = @th_clients
|
|
1411
|
+
prev_clients = @th_clients
|
|
1362
1412
|
@th_clients = {}
|
|
1363
1413
|
|
|
1364
1414
|
Thread.list.each{|th|
|
|
1365
1415
|
if tc = prev_clients[th]
|
|
1366
1416
|
@th_clients[th] = tc
|
|
1367
1417
|
else
|
|
1368
|
-
|
|
1418
|
+
create_thread_client(th)
|
|
1369
1419
|
end
|
|
1370
1420
|
}
|
|
1371
1421
|
end
|
|
@@ -1374,17 +1424,17 @@ module DEBUGGER__
|
|
|
1374
1424
|
if @th_clients.has_key? th
|
|
1375
1425
|
# TODO: NG?
|
|
1376
1426
|
else
|
|
1377
|
-
|
|
1427
|
+
create_thread_client th
|
|
1378
1428
|
end
|
|
1379
1429
|
end
|
|
1380
1430
|
|
|
1381
|
-
private def
|
|
1431
|
+
private def create_thread_client th
|
|
1382
1432
|
# TODO: Ractor support
|
|
1383
1433
|
raise "Only session_server can create thread_client" unless Thread.current == @session_server
|
|
1384
1434
|
@th_clients[th] = ThreadClient.new((@tc_id += 1), @q_evt, Queue.new, th)
|
|
1385
1435
|
end
|
|
1386
1436
|
|
|
1387
|
-
private def ask_thread_client th
|
|
1437
|
+
private def ask_thread_client th
|
|
1388
1438
|
# TODO: Ractor support
|
|
1389
1439
|
q2 = Queue.new
|
|
1390
1440
|
# tc, output, ev, @internal_info, *ev_args = evt
|
|
@@ -1395,30 +1445,18 @@ module DEBUGGER__
|
|
|
1395
1445
|
end
|
|
1396
1446
|
|
|
1397
1447
|
# can be called by other threads
|
|
1398
|
-
def
|
|
1448
|
+
def get_thread_client th = Thread.current
|
|
1399
1449
|
if @th_clients.has_key? th
|
|
1400
1450
|
@th_clients[th]
|
|
1401
1451
|
else
|
|
1402
1452
|
if Thread.current == @session_server
|
|
1403
|
-
|
|
1453
|
+
create_thread_client th
|
|
1404
1454
|
else
|
|
1405
1455
|
ask_thread_client th
|
|
1406
1456
|
end
|
|
1407
1457
|
end
|
|
1408
1458
|
end
|
|
1409
1459
|
|
|
1410
|
-
private def thread_stopper
|
|
1411
|
-
@thread_stopper ||= TracePoint.new(:line) do
|
|
1412
|
-
# run on each thread
|
|
1413
|
-
tc = ThreadClient.current
|
|
1414
|
-
next if tc.management?
|
|
1415
|
-
next unless tc.running?
|
|
1416
|
-
next if tc == @tc
|
|
1417
|
-
|
|
1418
|
-
tc.on_pause
|
|
1419
|
-
end
|
|
1420
|
-
end
|
|
1421
|
-
|
|
1422
1460
|
private def running_thread_clients_count
|
|
1423
1461
|
@th_clients.count{|th, tc|
|
|
1424
1462
|
next if tc.management?
|
|
@@ -1435,15 +1473,27 @@ module DEBUGGER__
|
|
|
1435
1473
|
}.compact
|
|
1436
1474
|
end
|
|
1437
1475
|
|
|
1476
|
+
private def thread_stopper
|
|
1477
|
+
TracePoint.new(:line) do
|
|
1478
|
+
# run on each thread
|
|
1479
|
+
tc = ThreadClient.current
|
|
1480
|
+
next if tc.management?
|
|
1481
|
+
next unless tc.running?
|
|
1482
|
+
next if tc == @tc
|
|
1483
|
+
|
|
1484
|
+
tc.on_pause
|
|
1485
|
+
end
|
|
1486
|
+
end
|
|
1487
|
+
|
|
1438
1488
|
private def stop_all_threads
|
|
1439
1489
|
return if running_thread_clients_count == 0
|
|
1440
1490
|
|
|
1441
|
-
stopper = thread_stopper
|
|
1491
|
+
stopper = @thread_stopper
|
|
1442
1492
|
stopper.enable unless stopper.enabled?
|
|
1443
1493
|
end
|
|
1444
1494
|
|
|
1445
1495
|
private def restart_all_threads
|
|
1446
|
-
stopper = thread_stopper
|
|
1496
|
+
stopper = @thread_stopper
|
|
1447
1497
|
stopper.disable if stopper.enabled?
|
|
1448
1498
|
|
|
1449
1499
|
waiting_thread_clients.each{|tc|
|
|
@@ -1550,11 +1600,41 @@ module DEBUGGER__
|
|
|
1550
1600
|
|
|
1551
1601
|
frames = exc.instance_variable_get(:@__debugger_postmortem_frames)
|
|
1552
1602
|
@postmortem = true
|
|
1553
|
-
ThreadClient.current.suspend :postmortem, postmortem_frames: frames
|
|
1603
|
+
ThreadClient.current.suspend :postmortem, postmortem_frames: frames, postmortem_exc: exc
|
|
1554
1604
|
ensure
|
|
1555
1605
|
@postmortem = false
|
|
1556
1606
|
end
|
|
1557
1607
|
|
|
1608
|
+
def capture_exception_frames *exclude_path
|
|
1609
|
+
postmortem_hook = TracePoint.new(:raise){|tp|
|
|
1610
|
+
exc = tp.raised_exception
|
|
1611
|
+
frames = DEBUGGER__.capture_frames(__dir__)
|
|
1612
|
+
|
|
1613
|
+
exclude_path.each{|ex|
|
|
1614
|
+
if Regexp === ex
|
|
1615
|
+
frames.delete_if{|e| ex =~ e.path}
|
|
1616
|
+
else
|
|
1617
|
+
frames.delete_if{|e| e.path.start_with? ex.to_s}
|
|
1618
|
+
end
|
|
1619
|
+
}
|
|
1620
|
+
exc.instance_variable_set(:@__debugger_postmortem_frames, frames)
|
|
1621
|
+
}
|
|
1622
|
+
postmortem_hook.enable
|
|
1623
|
+
|
|
1624
|
+
begin
|
|
1625
|
+
yield
|
|
1626
|
+
nil
|
|
1627
|
+
rescue Exception => e
|
|
1628
|
+
if e.instance_variable_defined? :@__debugger_postmortem_frames
|
|
1629
|
+
e
|
|
1630
|
+
else
|
|
1631
|
+
raise
|
|
1632
|
+
end
|
|
1633
|
+
ensure
|
|
1634
|
+
postmortem_hook.disable
|
|
1635
|
+
end
|
|
1636
|
+
end
|
|
1637
|
+
|
|
1558
1638
|
def postmortem=(is_enable)
|
|
1559
1639
|
if is_enable
|
|
1560
1640
|
unless @postmortem_hook
|
|
@@ -1792,7 +1872,7 @@ module DEBUGGER__
|
|
|
1792
1872
|
::DEBUGGER__::SESSION.add_catch_breakpoint pat
|
|
1793
1873
|
end
|
|
1794
1874
|
|
|
1795
|
-
# String for
|
|
1875
|
+
# String for requiring location
|
|
1796
1876
|
# nil for -r
|
|
1797
1877
|
def self.require_location
|
|
1798
1878
|
locs = caller_locations
|
|
@@ -1930,13 +2010,17 @@ module DEBUGGER__
|
|
|
1930
2010
|
METHOD_ADDED_TRACKER = self.create_method_added_tracker
|
|
1931
2011
|
|
|
1932
2012
|
SHORT_INSPECT_LENGTH = 40
|
|
1933
|
-
|
|
2013
|
+
|
|
2014
|
+
def self.safe_inspect obj, max_length: SHORT_INSPECT_LENGTH, short: false
|
|
1934
2015
|
str = obj.inspect
|
|
1935
|
-
|
|
1936
|
-
|
|
2016
|
+
|
|
2017
|
+
if short && str.length > max_length
|
|
2018
|
+
str[0...max_length] + '...'
|
|
1937
2019
|
else
|
|
1938
2020
|
str
|
|
1939
2021
|
end
|
|
2022
|
+
rescue Exception => e
|
|
2023
|
+
str = "<#inspect raises #{e.inspect}>"
|
|
1940
2024
|
end
|
|
1941
2025
|
|
|
1942
2026
|
def self.warn msg
|
|
@@ -1970,6 +2054,14 @@ module DEBUGGER__
|
|
|
1970
2054
|
end
|
|
1971
2055
|
end
|
|
1972
2056
|
|
|
2057
|
+
def self.step_in &b
|
|
2058
|
+
if defined?(SESSION) && SESSION.active?
|
|
2059
|
+
SESSION.add_iseq_breakpoint RubyVM::InstructionSequence.of(b), oneshot: true
|
|
2060
|
+
end
|
|
2061
|
+
|
|
2062
|
+
yield
|
|
2063
|
+
end
|
|
2064
|
+
|
|
1973
2065
|
module ForkInterceptor
|
|
1974
2066
|
def fork(&given_block)
|
|
1975
2067
|
return super unless defined?(SESSION) && SESSION.active?
|
|
@@ -40,12 +40,10 @@ module DEBUGGER__
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
private def add_path path
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
rescue SystemCallError
|
|
48
|
-
end
|
|
43
|
+
src = File.read(path)
|
|
44
|
+
src = src.gsub("\r\n", "\n") # CRLF -> LF
|
|
45
|
+
@files[path] = SrcInfo.new(src.lines)
|
|
46
|
+
rescue SystemCallError
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
private def get_si iseq
|