module Byebug
def self.attach(steps_out, before)
events occur. Before entering byebug the init script is read.
Enters byebug right before (or right after if _before_ is false) return
def self.attach(steps_out, before) setup_cmd_line_args start run_init_script current_context.step_out(steps_out, before) end
def self.handle_post_mortem
prompt back to the user before program termination.
Saves information about the unhandled exception and gives a byebug
def self.handle_post_mortem return unless Byebug.raised_exception context = Byebug.raised_exception.__bb_context file = Byebug.raised_exception.__bb_file line = Byebug.raised_exception.__bb_line Byebug.handler.at_line(context, file, line) end
def interrupt
Interrupts the current thread
def interrupt current_context.interrupt end
def parse_host_and_port(host_port_spec)
def parse_host_and_port(host_port_spec) location = host_port_spec.split(':') location[1] ? [location[0], location[1].to_i] : ['localhost', location[0]] end
def run_init_script
are debugging, in the directory where you invoke byebug.
generic in your home directory, and another, specific to the program you
from your home directory. Thus, you can have more than one init file, one
working directory. This is only done if the current directory is different
Reads and executes the commands from init file (if any) in the current
Runs normal byebug initialization scripts.
def run_init_script home_rc = File.expand_path(File.join(ENV['HOME'].to_s, INIT_FILE)) run_script(home_rc) if File.exist?(home_rc) cwd_rc = File.expand_path(File.join('.', INIT_FILE)) run_script(cwd_rc) if File.exist?(cwd_rc) && cwd_rc != home_rc end
def run_script(file, verbose = false)
Runs a script file
def run_script(file, verbose = false) interface = ScriptInterface.new(file, verbose) processor = ControlCommandProcessor.new(interface) processor.process_commands end
def setup_cmd_line_args
Extracts debugged program from command line args
def setup_cmd_line_args unless $PROGRAM_NAME.include?('bin/byebug') self.mode = :attached return end self.mode = :standalone fail(NoScript, 'You must specify a program to debug...') if $ARGV.empty? program = which($ARGV.shift) program = which($ARGV.shift) if program == which('ruby') fail(NonExistentScript, "The script doesn't exist") unless program $PROGRAM_NAME = program end
def start_client(host = 'localhost', port = PORT)
Connects to the remote byebug
def start_client(host = 'localhost', port = PORT) handler.interface = LocalInterface.new puts 'Connecting to byebug server...' socket = TCPSocket.new(host, port) puts 'Connected.' catch(:exit) do while (line = socket.gets) case line when /^PROMPT (.*)$/ input = handler.interface.read_command(Regexp.last_match[1]) throw :exit unless input socket.puts input when /^CONFIRM (.*)$/ input = handler.interface.confirm(Regexp.last_match[1]) throw :exit unless input socket.puts input else puts line end end end socket.close end
def start_control(host = nil, ctrl_port = PORT + 1)
def start_control(host = nil, ctrl_port = PORT + 1) return @actual_control_port if @control_thread server = TCPServer.new(host, ctrl_port) @actual_control_port = server.addr[1] @control_thread = DebugThread.new do while (session = server.accept) handler.interface = RemoteInterface.new(session) ControlCommandProcessor.new(handler.interface).process_commands end end @actual_control_port end
def start_server(host = nil, port = PORT)
Starts a remote byebug
def start_server(host = nil, port = PORT) return if @thread handler.interface = nil start start_control(host, port == 0 ? 0 : port + 1) yield if block_given? mutex = Mutex.new proceed = ConditionVariable.new server = TCPServer.new(host, port) self.actual_port = server.addr[1] @thread = DebugThread.new do while (session = server.accept) handler.interface = RemoteInterface.new(session) mutex.synchronize { proceed.signal } if wait_connection end end mutex.synchronize { proceed.wait(mutex) } if wait_connection end
def which(cmd)
Borrowed from: http://stackoverflow.com/questions/2108727
Cross-platform way of finding an executable in the $PATH.
def which(cmd) return File.expand_path(cmd) if File.exist?(cmd) exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| exts.each do |ext| exe = File.join(path, "#{cmd}#{ext}") return exe if File.executable?(exe) && !File.directory?(exe) end end nil end