Module: DEBUGGER__
Overview
$VERBOSE = true
Constant Summary
-
CONFIG =
# File 'lib/debug/config.rb', line 459 -
CONFIG_MAP =
# File 'lib/debug/config.rb', line 60CONFIG_SET.map{|k, (ev, _)| [k, ev]}.to_h.freeze
-
CONFIG_SET =
# File 'lib/debug/config.rb', line 13{ # UI setting log_level: ['RUBY_DEBUG_LOG_LEVEL', "UI: Log level same as Logger", :loglevel, "WARN"], show_src_lines: ['RUBY_DEBUG_SHOW_SRC_LINES', "UI: Show n lines source code on breakpoint", :int, "10"], show_evaledsrc: ['RUBY_DEBUG_SHOW_EVALEDSRC', "UI: Show actually evaluated source", :bool, "false"], show_frames: ['RUBY_DEBUG_SHOW_FRAMES', "UI: Show n frames on breakpoint", :int, "2"], use_short_path: ['RUBY_DEBUG_USE_SHORT_PATH', "UI: Show shorten PATH (like $(Gem)/foo.rb)", :bool, "false"], no_color: ['RUBY_DEBUG_NO_COLOR', "UI: Do not use colorize", :bool, "false"], no_sigint_hook: ['RUBY_DEBUG_NO_SIGINT_HOOK', "UI: Do not suspend on SIGINT", :bool, "false"], no_reline: ['RUBY_DEBUG_NO_RELINE', "UI: Do not use Reline library", :bool, "false"], no_hint: ['RUBY_DEBUG_NO_HINT', "UI: Do not show the hint on the REPL", :bool, "false"], no_lineno: ['RUBY_DEBUG_NO_LINENO', "UI: Do not show line numbers", :bool, "false"], irb_console: ["RUBY_DEBUG_IRB_CONSOLE", "UI: Use IRB as the console", :bool, "false"], # control setting skip_path: ['RUBY_DEBUG_SKIP_PATH', "CONTROL: Skip showing/entering frames for given paths", :path], skip_nosrc: ['RUBY_DEBUG_SKIP_NOSRC', "CONTROL: Skip on no source code lines", :bool, "false"], keep_alloc_site:['RUBY_DEBUG_KEEP_ALLOC_SITE',"CONTROL: Keep allocation site and p, pp shows it", :bool, "false"], postmortem: ['RUBY_DEBUG_POSTMORTEM', "CONTROL: Enable postmortem debug", :bool, "false"], fork_mode: ['RUBY_DEBUG_FORK_MODE', "CONTROL: Control which process activates a debugger after fork (both/parent/child)", :forkmode, "both"], sigdump_sig: ['RUBY_DEBUG_SIGDUMP_SIG', "CONTROL: Sigdump signal", :bool, "false"], # boot setting nonstop: ['RUBY_DEBUG_NONSTOP', "BOOT: Nonstop mode", :bool, "false"], stop_at_load: ['RUBY_DEBUG_STOP_AT_LOAD',"BOOT: Stop at just loading location", :bool, "false"], init_script: ['RUBY_DEBUG_INIT_SCRIPT', "BOOT: debug command script path loaded at first stop"], commands: ['RUBY_DEBUG_COMMANDS', "BOOT: debug commands invoked at first stop. Commands should be separated by `;;`"], no_rc: ['RUBY_DEBUG_NO_RC', "BOOT: ignore loading ~/.rdbgrc(.rb)", :bool, "false"], history_file: ['RUBY_DEBUG_HISTORY_FILE',"BOOT: history file", :string, "~/.rdbg_history"], save_history: ['RUBY_DEBUG_SAVE_HISTORY',"BOOT: maximum save history lines", :int, "10000"], # remote setting open: ['RUBY_DEBUG_OPEN', "REMOTE: Open remote port (same as `rdbg --open` option)"], port: ['RUBY_DEBUG_PORT', "REMOTE: TCP/IP remote debugging: port"], host: ['RUBY_DEBUG_HOST', "REMOTE: TCP/IP remote debugging: host", :string, "127.0.0.1"], sock_path: ['RUBY_DEBUG_SOCK_PATH', "REMOTE: UNIX Domain Socket remote debugging: socket path"], sock_dir: ['RUBY_DEBUG_SOCK_DIR', "REMOTE: UNIX Domain Socket remote debugging: socket directory"], local_fs_map: ['RUBY_DEBUG_LOCAL_FS_MAP', "REMOTE: Specify local fs map", :path_map], skip_bp: ['RUBY_DEBUG_SKIP_BP', "REMOTE: Skip breakpoints if no clients are attached", :bool, 'false'], cookie: ['RUBY_DEBUG_COOKIE', "REMOTE: Cookie for negotiation"], session_name: ['RUBY_DEBUG_SESSION_NAME', "REMOTE: Session name for differentiating multiple sessions"], chrome_path: ['RUBY_DEBUG_CHROME_PATH', "REMOTE: Platform dependent path of Chrome (For more information, See [here](https://github.com/ruby/debug/pull/334/files#diff-5fc3d0a901379a95bc111b86cf0090b03f857edfd0b99a0c1537e26735698453R55-R64))"], # obsolete parent_on_fork: ['RUBY_DEBUG_PARENT_ON_FORK', "OBSOLETE: Keep debugging parent process on fork", :bool, "false"], }.freeze
-
LOG_LEVELS =
# File 'lib/debug/config.rb', line 4{ UNKNOWN: 0, FATAL: 1, ERROR: 2, WARN: 3, INFO: 4, DEBUG: 5 }.freeze
-
M_CLASS =
# File 'lib/debug/thread_client.rb', line 15method(:class).unbind
-
M_INSTANCE_VARIABLES =
# File 'lib/debug/thread_client.rb', line 13method(:instance_variables).unbind
-
M_INSTANCE_VARIABLE_GET =
# File 'lib/debug/thread_client.rb', line 14method(:instance_variable_get).unbind
-
M_KIND_OF_P =
# File 'lib/debug/thread_client.rb', line 17method(:kind_of?).unbind
-
M_METHOD =
# File 'lib/debug/thread_client.rb', line 19method(:method).unbind
-
M_NAME =
# File 'lib/debug/thread_client.rb', line 21method(:name).unbind
-
M_OBJECT_ID =
# File 'lib/debug/thread_client.rb', line 20method(:object_id).unbind
-
M_RESPOND_TO_P =
# File 'lib/debug/thread_client.rb', line 18method(:respond_to?).unbind
-
M_SINGLETON_CLASS =
# File 'lib/debug/thread_client.rb', line 16method(:singleton_class).unbind
-
SHORT_INSPECT_LENGTH =
Inspector
40
-
VERSION =
# File 'lib/debug/version.rb', line 4"1.9.2"
Class Attribute Summary
- .skip? ⇒ Boolean readonly
Class Method Summary
- .add_catch_breakpoint(pat)
-
.add_line_breakpoint(file, line, **kw)
manual configuration methods.
-
.check_dir_authority(path)
Unix domain socket configuration.
- .check_loglevel(level)
- .commands
-
.compare_path(a, b)
For case insensitive file system (like Windows) Note that this check is not enough because case sensitive/insensitive is depend on the file system.
- .create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
- .create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
- .debug(&b)
- .help
- .helps
- .info(msg)
- .load_rc
- .log(level, msg)
- .open(host: nil, port: , sock_path: nil, sock_dir: nil, nonstop: false, **kw)
- .open_tcp(host: nil, port:, nonstop: false, **kw)
- .open_unix(sock_path: nil, sock_dir: nil, nonstop: false, **kw)
-
.parse_help
Help.
-
.require_location
String for requiring location nil for -r.
- .safe_inspect(obj, max_length: SHORT_INSPECT_LENGTH, short: false)
-
.setup_initial_suspend
boot utilities.
- .skip_all
-
.start(nonstop: false, **kw)
start methods.
- .step_in(&b)
- .unix_domain_socket_dir
- .unix_domain_socket_homedir
- .unix_domain_socket_tmpdir
- .warn(msg)
Class Attribute Details
.skip? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/debug/session.rb', line 2298
def skip? @skip_all end
Class Method Details
.add_catch_breakpoint(pat)
[ GitHub ]# File 'lib/debug/session.rb', line 2187
def self.add_catch_breakpoint pat ::DEBUGGER__::SESSION.add_catch_breakpoint pat end
.add_line_breakpoint(file, line, **kw)
manual configuration methods
# File 'lib/debug/session.rb', line 2183
def self.add_line_breakpoint file, line, **kw ::DEBUGGER__::SESSION.add_line_breakpoint file, line, **kw end
.check_dir_authority(path)
Unix domain socket configuration
# File 'lib/debug/config.rb', line 463
def self. path fs = File.stat(path) unless (dir_uid = fs.uid) == (uid = Process.uid) raise "#{path} uid is #{dir_uid}, but Process.uid is #{uid}" end if fs.world_writable? && !fs.sticky? raise "#{path} is world writable but not sticky" end path end
.check_loglevel(level)
[ GitHub ]# File 'lib/debug/session.rb', line 2387
def self.check_loglevel level lv = LOG_LEVELS[level] config_lv = LOG_LEVELS[CONFIG[:log_level]] lv <= config_lv end
.commands
[ GitHub ]# File 'lib/debug/config.rb', line 570
def self.commands (defined?(@commands) && @commands) || (parse_help; @commands) end
.compare_path(a, b)
For case insensitive file system (like Windows) Note that this check is not enough because case sensitive/insensitive is depend on the file system. So this check is only roughly estimation.
See additional method definition at line 2433.
# File 'lib/debug/session.rb', line 2437
def self.compare_path(a, b) a&.downcase == b&.downcase end
.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
[ GitHub ]# File 'lib/debug/config.rb', line 521
def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir) suffix = "-#{Process.pid}" name = CONFIG[:session_name] suffix << "-#{name}" if name create_unix_domain_socket_name_prefix(base_dir) + suffix end
.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
[ GitHub ]# File 'lib/debug/config.rb', line 517
def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir) File.join(base_dir, "rdbg") end
.debug(&b)
[ GitHub ]# File 'lib/debug/session.rb', line 2393
def self.debug(&b) if check_loglevel :DEBUG log :DEBUG, b.call end end
.help
[ GitHub ]# File 'lib/debug/config.rb', line 574
def self.help r = [] self.helps.each{|cat, cmds| r << "### #{cat}" r << '' cmds.each{|_, desc| r << desc } r << '' } r.join("\n") end
.helps
[ GitHub ]# File 'lib/debug/config.rb', line 566
def self.helps (defined?(@helps) && @helps) || parse_help end
.info(msg)
[ GitHub ]# File 'lib/debug/session.rb', line 2383
def self.info msg log :INFO, msg end
.load_rc
[ GitHub ]# File 'lib/debug/session.rb', line 2303
def self.load_rc [[File. ('~/.rdbgrc'), true], [File. ('~/.rdbgrc.rb'), true], # ['./.rdbgrc', true], # disable because of security concern [CONFIG[:init_script], false], ].each{|(path, rc)| next unless path next if rc && CONFIG[:no_rc] # ignore rc if File.file? path if path.end_with?('.rb') load path else ::DEBUGGER__::SESSION.add_preset_commands path, File.readlines(path) end elsif !rc warn "Not found: #{path}" end } # given debug commands if CONFIG[:commands] cmds = CONFIG[:commands].split(';;') ::DEBUGGER__::SESSION.add_preset_commands "commands", cmds, kick: false, continue: false end end
.log(level, msg)
[ GitHub ]# File 'lib/debug/session.rb', line 2399
def self.log level, msg if check_loglevel level @logfile = STDERR unless defined? @logfile return if @logfile.closed? if defined? SESSION pi = SESSION.process_info process_info = pi ? "[#{pi}]" : nil end if level == :WARN # :WARN on debugger is general information @logfile.puts "DEBUGGER#{process_info}: #{msg}" @logfile.flush else @logfile.puts "DEBUGGER#{process_info} (#{level}): #{msg}" @logfile.flush end end end
.open(host: nil, port: , sock_path: nil, sock_dir: nil, nonstop: false, **kw)
[ GitHub ]# File 'lib/debug/session.rb', line 2225
def self.open host: nil, port: CONFIG[:port], sock_path: nil, sock_dir: nil, nonstop: false, **kw CONFIG.set_config(**kw) require_relative 'server' if port || CONFIG[:open] == 'chrome' || (!::Addrinfo.respond_to?(:unix)) open_tcp host: host, port: (port || 0), nonstop: nonstop else open_unix sock_path: sock_path, sock_dir: sock_dir, nonstop: nonstop end end
.open_tcp(host: nil, port:, nonstop: false, **kw)
[ GitHub ]# File 'lib/debug/session.rb', line 2236
def self.open_tcp host: nil, port:, nonstop: false, **kw CONFIG.set_config(**kw) require_relative 'server' if defined? SESSION SESSION.reset_ui UI_TcpServer.new(host: host, port: port) else initialize_session{ UI_TcpServer.new(host: host, port: port) } end setup_initial_suspend unless nonstop end
.open_unix(sock_path: nil, sock_dir: nil, nonstop: false, **kw)
[ GitHub ]# File 'lib/debug/session.rb', line 2249
def self.open_unix sock_path: nil, sock_dir: nil, nonstop: false, **kw CONFIG.set_config(**kw) require_relative 'server' if defined? SESSION SESSION.reset_ui UI_UnixDomainServer.new(sock_dir: sock_dir, sock_path: sock_path) else initialize_session{ UI_UnixDomainServer.new(sock_dir: sock_dir, sock_path: sock_path) } end setup_initial_suspend unless nonstop end
.parse_help
Help
# File 'lib/debug/config.rb', line 530
def self.parse_help helps = Hash.new{|h, k| h[k] = []} desc = cat = nil cmds = Hash.new File.read(File.join(__dir__, 'session.rb'), encoding: Encoding::UTF_8).each_line do |line| case line when /\A\s*### (.+)/ cat = $1 break if $1 == 'END' when /\A register_command (.+)/ next unless cat next unless desc ws = [] $1.gsub(/'([a-z]+)'/){|w| ws << $1 } helps[cat] << [ws, desc] desc = nil max_w = ws.max_by{|w| w.length} ws.each{|w| cmds[w] = max_w } when /\A\s+# (\s*\*.+)/ if desc desc << "\n" + $1 else desc = $1 end end end @commands = cmds @helps = helps end
.require_location
String for requiring location nil for -r
# File 'lib/debug/session.rb', line 2193
def self.require_location locs = caller_locations dir_prefix = /#{Regexp.escape(__dir__)}/ locs.each do |loc| case loc.absolute_path when dir_prefix when %r{rubygems/core_ext/kernel_require\.rb} when %r{bundled_gems\.rb} else return loc if loc.absolute_path end end nil end
.safe_inspect(obj, max_length: SHORT_INSPECT_LENGTH, short: false)
[ GitHub ]# File 'lib/debug/session.rb', line 2361
def self.safe_inspect obj, max_length: SHORT_INSPECT_LENGTH, short: false if short LimitedPP.pp(obj, max_length) else obj.inspect end rescue NoMethodError => e klass, oid = M_CLASS.bind_call(obj), M_OBJECT_ID.bind_call(obj) if obj == (r = e.receiver) "<\##{klass.name}#{oid} does not have \#inspect>" else rklass, roid = M_CLASS.bind_call(r), M_OBJECT_ID.bind_call(r) "<\##{klass.name}:#{roid} contains <\##{rklass}:#{roid} and it does not have #inspect>" end rescue Exception => e "<#inspect raises #{e.inspect}>" end
.setup_initial_suspend
boot utilities
# File 'lib/debug/session.rb', line 2264
def self.setup_initial_suspend if !CONFIG[:nonstop] case when CONFIG[:stop_at_load] add_line_breakpoint __FILE__, __LINE__ + 1, oneshot: true, hook_call: false nil # stop here when path = ENV['RUBY_DEBUG_INITIAL_SUSPEND_PATH'] add_line_breakpoint path, 0, oneshot: true, hook_call: false when loc = ::DEBUGGER__.require_location # require 'debug/start' or 'debug' add_line_breakpoint loc.absolute_path, loc.lineno + 1, oneshot: true, hook_call: false else # -r add_line_breakpoint $0, 0, oneshot: true, hook_call: false end end end
.skip_all
[ GitHub ]# File 'lib/debug/session.rb', line 2294
def skip_all @skip_all = true end
.start(nonstop: false, **kw)
start methods
# File 'lib/debug/session.rb', line 2211
def self.start nonstop: false, **kw CONFIG.set_config(**kw) if CONFIG[:open] open nonstop: nonstop, **kw else unless defined? SESSION require_relative 'local' initialize_session{ UI_LocalConsole.new } end setup_initial_suspend unless nonstop end end
.step_in(&b)
[ GitHub ]# File 'lib/debug/session.rb', line 2420
def self.step_in &b if defined?(SESSION) && SESSION.active? SESSION.add_iseq_breakpoint RubyVM::InstructionSequence.of(b), oneshot: true end yield end
.unix_domain_socket_dir
[ GitHub ]# File 'lib/debug/config.rb', line 504
def self.unix_domain_socket_dir case when path = CONFIG[:sock_dir] when path = ENV['XDG_RUNTIME_DIR'] when path = unix_domain_socket_tmpdir when path = unix_domain_socket_homedir else raise 'specify RUBY_DEBUG_SOCK_DIR environment variable.' end path end
.unix_domain_socket_homedir
[ GitHub ]# File 'lib/debug/config.rb', line 492
def self.unix_domain_socket_homedir if home = ENV['HOME'] path = File.join(home, '.rdbg-sock') unless File.exist?(path) Dir.mkdir(path, 0700) end (path) end end
.unix_domain_socket_tmpdir
[ GitHub ]# File 'lib/debug/config.rb', line 477
def self.unix_domain_socket_tmpdir require 'tmpdir' if tmpdir = Dir.tmpdir path = File.join(tmpdir, "rdbg-#{Process.uid}") unless File.exist?(path) d = Dir.mktmpdir File.rename(d, path) end (path) end end
.warn(msg)
[ GitHub ]# File 'lib/debug/session.rb', line 2379
def self.warn msg log :WARN, msg end