module DEBUGGER__

$VERBOSE = true

Constants

CONFIG
CONFIG_MAP
CONFIG_SET
FrameInfo
LOG_LEVELS
M_CLASS
M_INSTANCE_VARIABLES
M_INSTANCE_VARIABLE_GET
M_KIND_OF_P
M_METHOD
M_OBJECT_ID
M_RESPOND_TO_P
M_SINGLETON_CLASS
PresetCommands
SHORT_INSPECT_LENGTH

Inspector

SessionCommand
VERSION

Public Class Methods

add_catch_breakpoint(pat) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2143
def self.add_catch_breakpoint pat
  ::DEBUGGER__::SESSION.add_catch_breakpoint pat
end
add_line_breakpoint(file, line, **kw) click to toggle source

manual configuration methods

# File debug-1.7.1/lib/debug/session.rb, line 2139
def self.add_line_breakpoint file, line, **kw
  ::DEBUGGER__::SESSION.add_line_breakpoint file, line, **kw
end
check_dir_authority(path) click to toggle source

Unix domain socket configuration

# File debug-1.7.1/lib/debug/config.rb, line 422
def self.check_dir_authority 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
  unless (dir_mode = fs.mode) == 040700 # 4: dir, 7:rwx
    raise "#{path}'s mode is #{dir_mode.to_s(8)} (should be 040700)"
  end

  path
end
check_loglevel(level) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2342
def self.check_loglevel level
  lv = LOG_LEVELS[level]
  config_lv = LOG_LEVELS[CONFIG[:log_level]]
  lv <= config_lv
end
commands() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 526
def self.commands
  (defined?(@commands) && @commands) || (parse_help; @commands)
end
compare_path(a, b) click to toggle source

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.

# File debug-1.7.1/lib/debug/session.rb, line 2388
def self.compare_path(a, b)
  a&.downcase == b&.downcase
end
create_unix_domain_socket_name(base_dir = unix_domain_socket_dir) click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 480
def self.create_unix_domain_socket_name(base_dir = unix_domain_socket_dir)
  create_unix_domain_socket_name_prefix(base_dir) + "-#{Process.pid}"
end
create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir) click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 475
def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
  user = ENV['USER'] || 'UnknownUser'
  File.join(base_dir, "ruby-debug-#{user}")
end
debug(&b) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2348
def self.debug(&b)
  if check_loglevel :DEBUG
    log :DEBUG, b.call
  end
end
help() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 530
def self.help
  r = []
  self.helps.each{|cat, cmds|
    r << "### #{cat}"
    r << ''
    cmds.each{|_, desc|
      r << desc
    }
    r << ''
  }
  r.join("\n")
end
helps() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 522
def self.helps
  (defined?(@helps) && @helps) || parse_help
end
info(msg) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2338
def self.info msg
  log :INFO, msg
end
load_rc() click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2258
def self.load_rc
  [[File.expand_path('~/.rdbgrc'), true],
   [File.expand_path('~/.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) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2354
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: CONFIG[:port], sock_path: nil, sock_dir: nil, nonstop: false, **kw) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2180
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) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2191
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) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2204
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() click to toggle source

Help

# File debug-1.7.1/lib/debug/config.rb, line 486
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() click to toggle source

String for requiring location nil for -r

# File debug-1.7.1/lib/debug/session.rb, line 2149
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}
    else
      return loc if loc.absolute_path
    end
  end
  nil
end
safe_inspect(obj, max_length: SHORT_INSPECT_LENGTH, short: false) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2316
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() click to toggle source

boot utilities

# File debug-1.7.1/lib/debug/session.rb, line 2219
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?() click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2253
def skip?
  @skip_all
end
skip_all() click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2249
def skip_all
  @skip_all = true
end
start(nonstop: false, **kw) click to toggle source

start methods

# File debug-1.7.1/lib/debug/session.rb, line 2166
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() { || ... } click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2375
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() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 462
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() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 450
def self.unix_domain_socket_homedir
  if home = ENV['HOME']
    path = File.join(home, '.ruby-debug-sock')

    unless File.exist?(path)
      Dir.mkdir(path, 0700)
    end

    check_dir_authority(path)
  end
end
unix_domain_socket_tmpdir() click to toggle source
# File debug-1.7.1/lib/debug/config.rb, line 435
def self.unix_domain_socket_tmpdir
  require 'tmpdir'

  if tmpdir = Dir.tmpdir
    path = File.join(tmpdir, "ruby-debug-sock-#{Process.uid}")

    unless File.exist?(path)
      d = Dir.mktmpdir
      File.rename(d, path)
    end

    check_dir_authority(path)
  end
end
warn(msg) click to toggle source
# File debug-1.7.1/lib/debug/session.rb, line 2334
def self.warn msg
  log :WARN, msg
end