class DEBUGGER__::Config
Experimental RBS support (using type sampling data from the type_fusion
project).
# sig/debug/config.rbs class DEBUGGER__::Config def []: (Symbol key) -> Symbol end
def self.config
def self.config @config end
def self.config_to_env_hash config
def self.config_to_env_hash config CONFIG_MAP.each_with_object({}){|(key, evname), env| unless config[key].nil? case CONFIG_SET[key][2] when :path valstr = config[key].map{|e| e.kind_of?(Regexp) ? e.inspect : e}.join(':') when :path_map valstr = config[key].map{|e| e.join(':')}.join(',') else valstr = config[key].to_s end env[evname] = valstr end } end
def self.parse_argv argv
def self.parse_argv argv config = { mode: :start, no_color: (nc = ENV['NO_COLOR']) && !nc.empty?, } CONFIG_MAP.each{|key, evname| if val = ENV[evname] config[key] = parse_config_value(key, val) end } return config if !argv || argv.empty? if argv.kind_of? String require 'shellwords' argv = Shellwords.split(argv) end require 'optparse' require_relative 'version' have_shown_version = false opt = OptionParser.new do |o| o.banner = "#{$0} [options] -- [debuggee options]" o.separator '' o.version = ::DEBUGGER__::VERSION o.separator 'Debug console mode:' o.on('-n', '--nonstop', 'Do not stop at the beginning of the script.') do config[:nonstop] = '1' end o.on('-e DEBUG_COMMAND', 'Execute debug command at the beginning of the script.') do |cmd| config[:commands] ||= '' config[:commands] += cmd + ';;' end o.on('-x FILE', '--init-script=FILE', 'Execute debug command in the FILE.') do |file| config[:init_script] = file end o.on('--no-rc', 'Ignore ~/.rdbgrc') do config[:no_rc] = true end o.on('--no-color', 'Disable colorize') do config[:no_color] = true end o.on('--no-sigint-hook', 'Disable to trap SIGINT') do config[:no_sigint_hook] = true end o.on('-c', '--command', 'Enable command mode.', 'The first argument should be a command name in $PATH.', 'Example: \'rdbg -c bundle exec rake test\'') do config[:command] = true end o.separator '' o.on('-O', '--open=[FRONTEND]', 'Start remote debugging with opening the network port.', 'If TCP/IP options are not given, a UNIX domain socket will be used.', 'If FRONTEND is given, prepare for the FRONTEND.', 'Now rdbg, vscode and chrome is supported.') do |f| case f # some format patterns are not documented yet when nil config[:open] = true when /\A\d\z/ config[:open] = true config[:port] = f.to_i when /\A(\S+):(\d+)\z/ config[:open] = true config[:host] = $1 config[:port] = $2.to_i when 'tcp' config[:open] = true config[:port] ||= 0 when 'vscode', 'chrome', 'cdp' config[:open] = f&.downcase else raise "Unknown option for --open: #{f}" end end o.on('--sock-path=SOCK_PATH', 'UNIX Domain socket path') do |path| config[:sock_path] = path end o.on('--port=PORT', 'Listening TCP/IP port') do |port| config[:port] = port end o.on('--host=HOST', 'Listening TCP/IP host') do |host| config[:host] = host end o.on('--cookie=COOKIE', 'Set a cookie for connection') do |c| config[:cookie] = c end o.on('--session-name=NAME', 'Session name') do |name| config[:session_name] = name end rdbg = 'rdbg' o.separator '' o.separator ' Debug console mode runs Ruby program with the debug console.' o.separator '' o.separator " '#{rdbg} target.rb foo bar' starts like 'ruby target.rb foo bar'." o.separator " '#{rdbg} -- -r foo -e bar' starts like 'ruby -r foo -e bar'." o.separator " '#{rdbg} -c rake test' starts like 'rake test'." o.separator " '#{rdbg} -c -- rake test -t' starts like 'rake test -t'." o.separator " '#{rdbg} -c bundle exec rake test' starts like 'bundle exec rake test'." o.separator " '#{rdbg} -O target.rb foo bar' starts and accepts attaching with UNIX domain socket." o.separator " '#{rdbg} -O --port 1234 target.rb foo bar' starts accepts attaching with TCP/IP localhost:1234." o.separator " '#{rdbg} -O --port 1234 -- -r foo -e bar' starts accepts attaching with TCP/IP localhost:1234." o.separator " '#{rdbg} target.rb -O chrome --port 1234' starts and accepts connecting from Chrome Devtools with localhost:1234." o.separator '' o.separator 'Attach mode:' o.on('-A', '--attach', 'Attach to debuggee process.') do config[:mode] = :attach end o.separator '' o.separator ' Attach mode attaches the remote debug console to the debuggee process.' o.separator '' o.separator " '#{rdbg} -A' tries to connect via UNIX domain socket." o.separator " #{' ' * rdbg.size} If there are multiple processes are waiting for the" o.separator " #{' ' * rdbg.size} debugger connection, list possible debuggee names." o.separator " '#{rdbg} -A path' tries to connect via UNIX domain socket with given path name." o.separator " '#{rdbg} -A port' tries to connect to localhost:port via TCP/IP." o.separator " '#{rdbg} -A host port' tries to connect to host:port via TCP/IP." o.separator '' o.separator 'Other options:' o.on('-v', 'Show version number') do puts o.ver have_shown_version = true end o.on('--version', 'Show version number and exit') do puts o.ver exit end o.on("-h", "--help", "Print help") do puts o exit end o.on('--util=NAME', 'Utility mode (used by tools)') do |name| require_relative 'client' Client.util(name) exit end o.on('--stop-at-load', 'Stop immediately when the debugging feature is loaded.') do config[:stop_at_load] = true end o.separator '' o.separator 'NOTE' o.separator ' All messages communicated between a debugger and a debuggee are *NOT* encrypted.' o.separator ' Please use the remote debugging feature carefully.' end opt.parse!(argv) if argv.empty? case when have_shown_version && config[:mode] == :start exit end end config end
def self.parse_config_value name, valstr
def self.parse_config_value name, valstr return valstr unless valstr.kind_of? String case CONFIG_SET[name][2] when :bool case valstr when '1', 'true', 'TRUE', 'T' true else false end when :int valstr.to_i when :loglevel if DEBUGGER__::LOG_LEVELS[s = valstr.to_sym] s else raise "Unknown loglevel: #{valstr}" end when :forkmode case sym = valstr.to_sym when :parent, :child, :both, nil sym else raise "unknown fork mode: #{sym}" end when :path # array of String valstr.split(/:/).map{|e| if /\A\/(.+)\/\z/ =~ e Regexp.compile $1 else e end } when :path_map valstr.split(',').map{|e| e.split(':')} else valstr end end
def [](key)
Experimental RBS support (using type sampling data from the type_fusion
project).
def []: (Symbol key) -> Symbol
This signature was generated using 2 samples from 1 application.
def [](key) config[key] end
def []=(key, val)
def []=(key, val) set_config(key => val) end
def append_config key, val
def append_config key, val conf = config.dup if CONFIG_SET[key] if CONFIG_SET[key][2] == :path conf[key] = [*conf[key], *parse_config_value(key, val)]; else raise "not an Array type: #{key}" end else raise "Unknown configuration: #{key}" end update conf end
def config
def config lass.config
def disable_sigdump old_sig
def disable_sigdump old_sig ld_sig, @sigdump_sig_prev) mp_sig_prev = nil
def enable_sigdump sig
def enable_sigdump sig mp_sig_prev = trap(sig) do = [] << "Simple sigdump on #{Process.pid}" ad.list.each{|th| r << "Thread: #{th}" .backtrace.each{|loc| str << " #{loc}" r << '' RR.puts str
def if_updated old_conf, new_conf, key
def if_updated old_conf, new_conf, key ew = old_conf[key], new_conf[key] old, new if old != new
def initialize argv
def initialize argv if self.class.config raise 'Can not make multiple configurations in one process' end config = self.class.parse_argv(argv) # apply defaults CONFIG_SET.each do |k, config_detail| unless config.key?(k) default_value = config_detail[3] config[k] = parse_config_value(k, default_value) end end update config end
def inspect
def inspect config.inspect end
def parse_config_value name, valstr
def parse_config_value name, valstr lass.parse_config_value name, valstr
def set_config(**kw)
def set_config(**kw) conf = config.dup kw.each{|k, v| if CONFIG_MAP[k] conf[k] = parse_config_value(k, v) # TODO: ractor support else raise "Unknown configuration: #{k}" end } update conf end
def setup_sigdump old_sig = nil, sig = CONFIG[:sigdump_sig]
emergency simple sigdump.
def setup_sigdump old_sig = nil, sig = CONFIG[:sigdump_sig] d_sig && sig le_sigdump sig old_sig && !sig ble_sigdump old_sig old_sig && sig ble_sigdump old_sig le_sigdump sig
def update conf
def update conf old_conf = self.class.instance_variable_get(:@config) || {} # TODO: Use Ractor.make_shareable(conf) self.class.instance_variable_set(:@config, conf.freeze) # Post process if_updated old_conf, conf, :keep_alloc_site do |old, new| if new require 'objspace' ObjectSpace.trace_object_allocations_start end if old && !new ObjectSpace.trace_object_allocations_stop end end if_updated old_conf, conf, :postmortem do |_, new_p| if defined?(SESSION) SESSION.postmortem = new_p end end if_updated old_conf, conf, :sigdump_sig do |old_sig, new_sig| setup_sigdump old_sig, new_sig end if_updated old_conf, conf, :no_sigint_hook do |old, new| if defined?(SESSION) SESSION.set_no_sigint_hook old, new end end end