module DEBUGGER__ - debug: Ruby Standard Library Documentation

# 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_NAME
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.10.0/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) click to toggle source

manual configuration methods

    # File debug-1.10.0/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) click to toggle source

Unix domain socket configuration

    # File debug-1.10.0/lib/debug/config.rb, line 467
    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

      if fs.world_writable? && !fs.sticky?
        raise "#{path} is world writable but not sticky"
      end

      path
    end

check_loglevel(level) click to toggle source

    # File debug-1.10.0/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() click to toggle source

    # File debug-1.10.0/lib/debug/config.rb, line 574
    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.10.0/lib/debug/session.rb, line 2433
    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.10.0/lib/debug/config.rb, line 525
    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) click to toggle source

    # File debug-1.10.0/lib/debug/config.rb, line 521
    def self.create_unix_domain_socket_name_prefix(base_dir = unix_domain_socket_dir)
      File.join(base_dir, "rdbg")
    end

debug(&b) click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2393
    def self.debug(&b)
      if check_loglevel :DEBUG
        log :DEBUG, b.call
      end
    end

help() click to toggle source

    # File debug-1.10.0/lib/debug/config.rb, line 578
    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.10.0/lib/debug/config.rb, line 570
    def self.helps
      (defined?(@helps) && @helps) || parse_help
    end

info(msg) click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2383
    def self.info msg
      log :INFO, msg
    end

load_rc() click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2303
    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.10.0/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: CONFIG[:port], sock_path: nil, sock_dir: nil, nonstop: false, **kw) click to toggle source

    # File debug-1.10.0/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) click to toggle source

    # File debug-1.10.0/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) click to toggle source

    # File debug-1.10.0/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() click to toggle source

Help

    # File debug-1.10.0/lib/debug/config.rb, line 534
    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.10.0/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) click to toggle source

    # File debug-1.10.0/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() click to toggle source

boot utilities

    # File debug-1.10.0/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?() click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2298
    def skip?
      @skip_all
    end

skip_all() click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2294
    def skip_all
      @skip_all = true
    end

start(nonstop: false, **kw) click to toggle source

start methods

    # File debug-1.10.0/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() { || ... } click to toggle source

    # File debug-1.10.0/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() click to toggle source

    # File debug-1.10.0/lib/debug/config.rb, line 508
    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.10.0/lib/debug/config.rb, line 496
    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

        check_dir_authority(path)
      end
    end

unix_domain_socket_tmpdir() click to toggle source

    # File debug-1.10.0/lib/debug/config.rb, line 481
    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

        check_dir_authority(path)
      end
    end

warn(msg) click to toggle source

    # File debug-1.10.0/lib/debug/session.rb, line 2379
    def self.warn msg
      log :WARN, msg
    end