debug 1.6.3 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +19 -7
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +37 -14
- data/Rakefile +0 -0
- data/TODO.md +8 -8
- data/debug.gemspec +1 -1
- data/exe/rdbg +1 -1
- data/ext/debug/debug.c +15 -1
- data/ext/debug/extconf.rb +0 -0
- data/ext/debug/iseq_collector.c +0 -0
- data/lib/debug/abbrev_command.rb +77 -0
- data/lib/debug/breakpoint.rb +17 -11
- data/lib/debug/client.rb +26 -9
- data/lib/debug/color.rb +0 -0
- data/lib/debug/config.rb +34 -16
- data/lib/debug/console.rb +0 -0
- data/lib/debug/frame_info.rb +0 -0
- data/lib/debug/local.rb +16 -10
- data/lib/debug/open.rb +0 -0
- data/lib/debug/open_nonstop.rb +0 -0
- data/lib/debug/prelude.rb +1 -1
- data/lib/debug/server.rb +25 -21
- data/lib/debug/server_cdp.rb +292 -86
- data/lib/debug/server_dap.rb +132 -47
- data/lib/debug/session.rb +384 -204
- data/lib/debug/source_repository.rb +39 -19
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +196 -63
- data/lib/debug/tracer.rb +0 -0
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +7 -3
- data/misc/README.md.erb +9 -3
- metadata +5 -4
data/lib/debug/server_dap.rb
CHANGED
@@ -18,7 +18,7 @@ module DEBUGGER__
|
|
18
18
|
end
|
19
19
|
|
20
20
|
at_exit do
|
21
|
-
|
21
|
+
DEBUGGER__.skip_all
|
22
22
|
FileUtils.rm_rf dir if tempdir
|
23
23
|
end
|
24
24
|
|
@@ -128,7 +128,8 @@ module DEBUGGER__
|
|
128
128
|
|
129
129
|
case self
|
130
130
|
when UI_UnixDomainServer
|
131
|
-
|
131
|
+
# If the user specified a mapping, respect it, otherwise, make sure that no mapping is used
|
132
|
+
UI_DAP.local_fs_map_set CONFIG[:local_fs_map] || true
|
132
133
|
when UI_TcpServer
|
133
134
|
# TODO: loopback address can be used to connect other FS env, like Docker containers
|
134
135
|
# UI_DAP.local_fs_set if @local_addr.ipv4_loopback? || @local_addr.ipv6_loopback?
|
@@ -198,6 +199,13 @@ module DEBUGGER__
|
|
198
199
|
# supportsInstructionBreakpoints:
|
199
200
|
)
|
200
201
|
send_event 'initialized'
|
202
|
+
puts <<~WELCOME
|
203
|
+
Ruby REPL: You can run any Ruby expression here.
|
204
|
+
Note that output to the STDOUT/ERR printed on the TERMINAL.
|
205
|
+
[experimental]
|
206
|
+
`,COMMAND` runs `COMMAND` debug command (ex: `,info`).
|
207
|
+
`,help` to list all debug commands.
|
208
|
+
WELCOME
|
201
209
|
end
|
202
210
|
|
203
211
|
def send **kw
|
@@ -271,18 +279,24 @@ module DEBUGGER__
|
|
271
279
|
## boot/configuration
|
272
280
|
when 'launch'
|
273
281
|
send_response req
|
274
|
-
|
275
|
-
|
282
|
+
# `launch` runs on debuggee on the same file system
|
283
|
+
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
|
284
|
+
@nonstop = true
|
276
285
|
|
277
286
|
when 'attach'
|
278
287
|
send_response req
|
279
288
|
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
|
280
|
-
|
289
|
+
|
290
|
+
if req.dig('arguments', 'nonstop') == true
|
291
|
+
@nonstop = true
|
292
|
+
else
|
293
|
+
@nonstop = false
|
294
|
+
end
|
281
295
|
|
282
296
|
when 'configurationDone'
|
283
297
|
send_response req
|
284
298
|
|
285
|
-
if @
|
299
|
+
if @nonstop
|
286
300
|
@q_msg << 'continue'
|
287
301
|
else
|
288
302
|
if SESSION.in_subsession?
|
@@ -419,16 +433,30 @@ module DEBUGGER__
|
|
419
433
|
}
|
420
434
|
}
|
421
435
|
|
436
|
+
when 'evaluate'
|
437
|
+
expr = req.dig('arguments', 'expression')
|
438
|
+
if /\A\s*,(.+)\z/ =~ expr
|
439
|
+
dbg_expr = $1
|
440
|
+
send_response req,
|
441
|
+
result: "",
|
442
|
+
variablesReference: 0
|
443
|
+
debugger do: dbg_expr
|
444
|
+
else
|
445
|
+
@q_msg << req
|
446
|
+
end
|
422
447
|
when 'stackTrace',
|
423
448
|
'scopes',
|
424
449
|
'variables',
|
425
|
-
'evaluate',
|
426
450
|
'source',
|
427
451
|
'completions'
|
428
452
|
@q_msg << req
|
429
453
|
|
430
454
|
else
|
431
|
-
|
455
|
+
if respond_to? mid = "request_#{req['command']}"
|
456
|
+
send mid, req
|
457
|
+
else
|
458
|
+
raise "Unknown request: #{req.inspect}"
|
459
|
+
end
|
432
460
|
end
|
433
461
|
end
|
434
462
|
ensure
|
@@ -443,7 +471,11 @@ module DEBUGGER__
|
|
443
471
|
|
444
472
|
def puts result
|
445
473
|
# STDERR.puts "puts: #{result}"
|
446
|
-
|
474
|
+
send_event 'output', category: 'console', output: "#{result&.chomp}\n"
|
475
|
+
end
|
476
|
+
|
477
|
+
def ignore_output_on_suspend?
|
478
|
+
true
|
447
479
|
end
|
448
480
|
|
449
481
|
def event type, *args
|
@@ -488,6 +520,8 @@ module DEBUGGER__
|
|
488
520
|
end
|
489
521
|
|
490
522
|
class Session
|
523
|
+
include GlobalVariablesHelper
|
524
|
+
|
491
525
|
def find_waiting_tc id
|
492
526
|
@th_clients.each{|th, tc|
|
493
527
|
return tc if tc.id == id && tc.waiting?
|
@@ -534,8 +568,12 @@ module DEBUGGER__
|
|
534
568
|
if ref = @var_map[varid]
|
535
569
|
case ref[0]
|
536
570
|
when :globals
|
537
|
-
vars =
|
538
|
-
|
571
|
+
vars = safe_global_variables.sort.map do |name|
|
572
|
+
begin
|
573
|
+
gv = eval(name.to_s)
|
574
|
+
rescue Exception => e
|
575
|
+
gv = e.inspect
|
576
|
+
end
|
539
577
|
{
|
540
578
|
name: name,
|
541
579
|
value: gv.inspect,
|
@@ -580,6 +618,7 @@ module DEBUGGER__
|
|
580
618
|
if @frame_map[frame_id]
|
581
619
|
tid, fid = @frame_map[frame_id]
|
582
620
|
expr = req.dig('arguments', 'expression')
|
621
|
+
|
583
622
|
if tc = find_waiting_tc(tid)
|
584
623
|
request_tc [:dap, :evaluate, req, fid, expr, context]
|
585
624
|
else
|
@@ -684,10 +723,33 @@ module DEBUGGER__
|
|
684
723
|
end
|
685
724
|
end
|
686
725
|
|
726
|
+
class NaiveString
|
727
|
+
attr_reader :str
|
728
|
+
def initialize str
|
729
|
+
@str = str
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
687
733
|
class ThreadClient
|
688
|
-
|
734
|
+
MAX_LENGTH = 180
|
735
|
+
|
736
|
+
def value_inspect obj, short: true
|
689
737
|
# TODO: max length should be configuarable?
|
690
|
-
DEBUGGER__.safe_inspect obj, short:
|
738
|
+
str = DEBUGGER__.safe_inspect obj, short: short, max_length: MAX_LENGTH
|
739
|
+
|
740
|
+
if str.encoding == Encoding::UTF_8
|
741
|
+
str.scrub
|
742
|
+
else
|
743
|
+
str.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
|
744
|
+
end
|
745
|
+
end
|
746
|
+
|
747
|
+
def dap_eval b, expr, _context, prompt: '(repl_eval)'
|
748
|
+
begin
|
749
|
+
b.eval(expr.to_s, prompt)
|
750
|
+
rescue Exception => e
|
751
|
+
e
|
752
|
+
end
|
691
753
|
end
|
692
754
|
|
693
755
|
def process_dap args
|
@@ -702,9 +764,10 @@ module DEBUGGER__
|
|
702
764
|
frames = []
|
703
765
|
@target_frames.each_with_index do |frame, i|
|
704
766
|
next if i < start_frame
|
705
|
-
break if (levels -= 1) < 0
|
706
767
|
|
707
768
|
path = frame.realpath || frame.path
|
769
|
+
next if skip_path?(path) && !SESSION.stop_stepping?(path, frame.location.lineno)
|
770
|
+
break if (levels -= 1) < 0
|
708
771
|
source_name = path ? File.basename(path) : frame.location.to_s
|
709
772
|
|
710
773
|
if (path && File.exist?(path)) && (local_path = UI_DAP.remote_to_local_path(path))
|
@@ -754,7 +817,7 @@ module DEBUGGER__
|
|
754
817
|
name: 'Global variables',
|
755
818
|
presentationHint: 'globals',
|
756
819
|
variablesReference: 1, # GLOBAL
|
757
|
-
namedVariables:
|
820
|
+
namedVariables: safe_global_variables.size,
|
758
821
|
indexedVariables: 0,
|
759
822
|
expensive: false,
|
760
823
|
}]
|
@@ -791,14 +854,13 @@ module DEBUGGER__
|
|
791
854
|
}
|
792
855
|
when String
|
793
856
|
vars = [
|
794
|
-
variable('#
|
795
|
-
variable('#encoding', obj.encoding)
|
857
|
+
variable('#lengthddsfsd', obj.length),
|
858
|
+
variable('#encoding', obj.encoding),
|
796
859
|
]
|
860
|
+
printed_str = value_inspect(obj)
|
861
|
+
vars << variable('#dump', NaiveString.new(obj)) if printed_str.end_with?('...')
|
797
862
|
when Class, Module
|
798
|
-
vars
|
799
|
-
variable(iv, obj.instance_variable_get(iv))
|
800
|
-
}
|
801
|
-
vars.unshift variable('%ancestors', obj.ancestors[1..])
|
863
|
+
vars << variable('%ancestors', obj.ancestors[1..])
|
802
864
|
when Range
|
803
865
|
vars = [
|
804
866
|
variable('#begin', obj.begin),
|
@@ -806,10 +868,12 @@ module DEBUGGER__
|
|
806
868
|
]
|
807
869
|
end
|
808
870
|
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
871
|
+
unless NaiveString === obj
|
872
|
+
vars += M_INSTANCE_VARIABLES.bind_call(obj).sort.map{|iv|
|
873
|
+
variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv))
|
874
|
+
}
|
875
|
+
vars.unshift variable('#class', M_CLASS.bind_call(obj))
|
876
|
+
end
|
813
877
|
end
|
814
878
|
end
|
815
879
|
event! :dap_result, :variable, req, variables: (vars || []), tid: self.id
|
@@ -826,12 +890,7 @@ module DEBUGGER__
|
|
826
890
|
|
827
891
|
case context
|
828
892
|
when 'repl', 'watch'
|
829
|
-
|
830
|
-
result = b.eval(expr.to_s, '(DEBUG CONSOLE)')
|
831
|
-
rescue Exception => e
|
832
|
-
result = e
|
833
|
-
end
|
834
|
-
|
893
|
+
result = dap_eval b, expr, context, prompt: '(DEBUG CONSOLE)'
|
835
894
|
when 'hover'
|
836
895
|
case expr
|
837
896
|
when /\A\@\S/
|
@@ -841,7 +900,7 @@ module DEBUGGER__
|
|
841
900
|
message = "Error: Not defined instance variable: #{expr.inspect}"
|
842
901
|
end
|
843
902
|
when /\A\$\S/
|
844
|
-
|
903
|
+
safe_global_variables.each{|gvar|
|
845
904
|
if gvar.to_s == expr
|
846
905
|
result = eval(gvar.to_s)
|
847
906
|
break false
|
@@ -914,7 +973,11 @@ module DEBUGGER__
|
|
914
973
|
[Object, *b.eval('::Module.nesting')].reverse_each{|mod|
|
915
974
|
if cs.all?{|c|
|
916
975
|
if mod.const_defined?(c)
|
917
|
-
|
976
|
+
begin
|
977
|
+
mod = mod.const_get(c)
|
978
|
+
rescue Exception
|
979
|
+
false
|
980
|
+
end
|
918
981
|
else
|
919
982
|
false
|
920
983
|
end
|
@@ -927,11 +990,17 @@ module DEBUGGER__
|
|
927
990
|
end
|
928
991
|
|
929
992
|
def evaluate_result r
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
993
|
+
variable nil, r
|
994
|
+
end
|
995
|
+
|
996
|
+
def type_name obj
|
997
|
+
klass = M_CLASS.bind_call(obj)
|
998
|
+
|
999
|
+
begin
|
1000
|
+
klass.name || klass.to_s
|
1001
|
+
rescue Exception => e
|
1002
|
+
"<Error: #{e.message} (#{e.backtrace.first}>"
|
1003
|
+
end
|
935
1004
|
end
|
936
1005
|
|
937
1006
|
def variable_ name, obj, indexedVariables: 0, namedVariables: 0
|
@@ -942,15 +1011,31 @@ module DEBUGGER__
|
|
942
1011
|
vid = 0
|
943
1012
|
end
|
944
1013
|
|
945
|
-
|
1014
|
+
namedVariables += M_INSTANCE_VARIABLES.bind_call(obj).size
|
946
1015
|
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
1016
|
+
if NaiveString === obj
|
1017
|
+
str = obj.str.dump
|
1018
|
+
vid = indexedVariables = namedVariables = 0
|
1019
|
+
else
|
1020
|
+
str = value_inspect(obj)
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
if name
|
1024
|
+
{ name: name,
|
1025
|
+
value: str,
|
1026
|
+
type: type_name(obj),
|
1027
|
+
variablesReference: vid,
|
1028
|
+
indexedVariables: indexedVariables,
|
1029
|
+
namedVariables: namedVariables,
|
1030
|
+
}
|
1031
|
+
else
|
1032
|
+
{ result: str,
|
1033
|
+
type: type_name(obj),
|
1034
|
+
variablesReference: vid,
|
1035
|
+
indexedVariables: indexedVariables,
|
1036
|
+
namedVariables: namedVariables,
|
1037
|
+
}
|
1038
|
+
end
|
954
1039
|
end
|
955
1040
|
|
956
1041
|
def variable name, obj
|
@@ -960,7 +1045,7 @@ module DEBUGGER__
|
|
960
1045
|
when Hash
|
961
1046
|
variable_ name, obj, namedVariables: obj.size
|
962
1047
|
when String
|
963
|
-
variable_ name, obj, namedVariables: 3 # #
|
1048
|
+
variable_ name, obj, namedVariables: 3 # #length, #encoding, #to_str
|
964
1049
|
when Struct
|
965
1050
|
variable_ name, obj, namedVariables: obj.size
|
966
1051
|
when Class, Module
|