Skip to content

Commit

Permalink
DAP: introduce Rdbg Inspector
Browse files Browse the repository at this point in the history
  • Loading branch information
ono-max committed Apr 17, 2023
1 parent 7b27350 commit 4dc44d3
Show file tree
Hide file tree
Showing 6 changed files with 557 additions and 7 deletions.
245 changes: 245 additions & 0 deletions lib/debug/dap_custom/traceInspector.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
module DEBUGGER__
module DAP_TraceInspector
class MultiTracer < Tracer
MAX_LOG_SIZE = 4000
def initialize ui, evts, trace_params, **kw
@evts = evts
@log = []
@trace_params = trace_params
super(ui, **kw)
@type = 'multi'
end

attr_reader :log

def setup
@tracer = TracePoint.new(*@evts){|tp|
next if skip?(tp)

case tp.event
when :call, :c_call, :b_call
if @trace_params
params = get_params tp
end
append(call_trace_log(tp, params: params))
when :return, :c_return, :b_return
return_str = DEBUGGER__.safe_inspect(tp.return_value, short: true, max_length: 120)
append(call_trace_log(tp, return_str: return_str))
when :line
append(line_trace_log(tp))
end
}
end

def get_params tp
b = tp.binding
tp.parameters.map{|_type, name|
begin
{ name: name, value: DEBUGGER__.safe_inspect(b.local_variable_get(name), short: true, max_length: 120) }
rescue NameError, TypeError
nil
end
}.compact
end

def call_identifier_str tp
if tp.defined_class
minfo(tp)
else
"block"
end
end

def append log
if @log.size >= MAX_LOG_SIZE
@log.shift
end
@log << log
end

def call_trace_log tp, return_str: nil, params: nil
log = {
depth: DEBUGGER__.frame_depth,
name: call_identifier_str(tp),
threadId: Thread.current.instance_variable_get(:@__thread_client_id),
location: {
path: tp.path,
line: tp.lineno
}
}
log[:returnValue] = return_str if return_str
log[:parameters] = params if params && params.size > 0
log
end

def line_trace_log tp
{
depth: DEBUGGER__.frame_depth,
threadId: Thread.current.instance_variable_get(:@__thread_client_id),
location: {
path: tp.path,
line: tp.lineno
}
}
end

def skip? tp
super || !@evts.include?(tp.event)
end

def skip_with_pattern?(tp)
super && !tp.method_id&.match?(@pattern)
end
end

module Custom_UI_DAP
def custom_dap_request_rdbgTraceInspector(req)
@q_msg << req
end
end

module Custom_Session
def process_trace_cmd req
cmd = req.dig('arguments', 'subCommand')
case cmd
when 'enable'
events = req.dig('arguments', 'events')
evts = []
trace_params = false
filter = req.dig('arguments', 'filterRegExp')
events.each{|evt|
case evt
when 'traceLine'
evts << :line
when 'traceCall'
evts << :call
evts << :c_call
evts << :b_call
when 'traceReturn'
evts << :return
evts << :c_return
evts << :b_return
when 'traceParams'
trace_params = true
else
raise "unknown trace type #{evt}"
end
}
add_tracer MultiTracer.new @ui, evts, trace_params, pattern: filter
@ui.respond req, {}
when 'disable'
if t = find_multi_trace
t.disable
end
@ui.respond req, {}
when 'collect'
logs = []
if t = find_multi_trace
logs = t.log
end
@ui.respond req, logs: logs
else
raise "Unknown trace sub command #{cmd}"
end
return :retry
end

def find_multi_trace
@tracers.values.each{|t|
if t.type == 'multi'
return t
end
}
return nil
end

def process_record_cmd req
cmd = req.dig('arguments', 'subCommand')
case cmd
when 'enable'
request_tc [:record, :on]
@ui.respond req, {}
when 'disable'
request_tc [:record, :off]
@ui.respond req, {}
when 'step'
tid = req.dig('arguments', 'threadId')
count = req.dig('arguments', 'count')
if tc = find_waiting_tc(tid)
@ui.respond req, {}
tc << [:step, :in, count]
else
fail_response req
end
when 'stepBack'
tid = req.dig('arguments', 'threadId')
count = req.dig('arguments', 'count')
if tc = find_waiting_tc(tid)
@ui.respond req, {}
tc << [:step, :back, count]
else
fail_response req
end
when 'collect'
tid = req.dig('arguments', 'threadId')
if tc = find_waiting_tc(tid)
tc << [:dap, :rdbgTraceInspector, req]
else
fail_response req
end
else
raise "Unknown record sub command #{cmd}"
end
end

def custom_dap_request_rdbgTraceInspector(req)
cmd = req.dig('arguments', 'command')
case cmd
when 'trace'
process_trace_cmd req
when 'record'
process_record_cmd req
else
raise "Unknown command #{cmd}"
end
end

def custom_dap_request_event_rdbgTraceInspector(req, result)
@ui.respond req, result
end
end

module Custom_ThreadClient
def custom_dap_request_rdbgTraceInspector(req)
cmd = req.dig('arguments', 'command')
if cmd == 'record'
logs = []
log_index = nil
unless @recorder.nil?
log_index = @recorder.log_index
@recorder.log.each{|frames|
crt_frame = frames[0]
log = {
name: crt_frame.name,
location: {
path: crt_frame.location.path,
line: crt_frame.location.lineno,
},
depth: crt_frame.frame_depth
}
if params = crt_frame.get_params
log[:parameters] = params
end
logs << log
}
end
event! :protocol_result, :rdbgTraceInspector, req, logs: logs, stoppedIndex: log_index
else
raise "Unknown command #{cmd}"
end
end
end

::DEBUGGER__::SESSION.extend_feature session: Custom_Session, thread_client: Custom_ThreadClient, ui: Custom_UI_DAP
end
end
11 changes: 11 additions & 0 deletions lib/debug/frame_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ def local_variables
end
end

def get_params
case frame_type
when :block
parameters_info
when :method
parameters_info
else
nil
end
end

def parameters_info
vars = iseq.parameters_symbols
vars.map{|var|
Expand Down
12 changes: 12 additions & 0 deletions lib/debug/server_dap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,14 @@ def recv_request
retry
end

def load_rdbgExtension req
if exts = req.dig('arguments', 'rdbgExtension')
exts.each{|ext|
require_relative "dap_custom/#{File.basename(ext)}"
}
end
end

def process
while req = recv_request
raise "not a request: #{req.inspect}" unless req['type'] == 'request'
Expand All @@ -288,6 +296,8 @@ def process
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap') || true
@nonstop = true

load_rdbgExtension req

when 'attach'
send_response req
UI_DAP.local_fs_map_set req.dig('arguments', 'localfs') || req.dig('arguments', 'localfsMap')
Expand All @@ -298,6 +308,8 @@ def process
@nonstop = false
end

load_rdbgExtension req

when 'configurationDone'
send_response req

Expand Down
14 changes: 7 additions & 7 deletions lib/debug/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,13 @@ def before_fork need_lock = true
def after_fork_parent
@ui.after_fork_parent
end

# experimental API
def extend_feature session: nil, thread_client: nil, ui: nil
Session.include session if session
ThreadClient.include thread_client if thread_client
@ui.extend ui if ui
end
end

class ProcessGroup
Expand Down Expand Up @@ -2147,13 +2154,6 @@ def flush
end
end

# experimental API
def extend_feature session: nil, thread_client: nil, ui: nil
Session.include session if session
ThreadClient.include thread_client if thread_client
@ui.extend ui if ui
end

# manual configuration methods

def self.add_line_breakpoint file, line, **kw
Expand Down
Loading

0 comments on commit 4dc44d3

Please sign in to comment.