Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix Debugger.start in ruby-debug compat mode

  • Loading branch information...
commit 6d6afc5ca4467b80f12d94e563b4c04fc9e5221c 1 parent 19febf3
Evan Phoenix authored
View
8 doc/content/tools/debugger.html
@@ -18,8 +18,8 @@
class Toast
attr_accessor :setting
def initialize
- require 'debugger'
- Debugger.start
+ require 'rubinius/debugger'
+ Rubinius::Debugger.start
@setting = :brown
end
end
@@ -31,7 +31,7 @@
$ rbx app.rb
| Breakpoint: Toast#initialize at app.rb:5 (15)
- | 5: Debugger.start
+ | 5: Rubinius::Debugger.start
debug> help
help: Show information about debugger commands
b, break, brk: Set a breakpoint at a point in a method
@@ -98,7 +98,7 @@
$ rbx -Xdebug bug.rb
| Breakpoint: Rubinius::Loader#debugger at kernel/loader.rb:424 (34)
- | 424: Debugger.start
+ | 424: Rubinius::Debugger.start
debug> b Object#problem_code:2
* Unable to find method 'problem_code' in Object
| Would you like to defer this breakpoint to later? [y/n] y
View
4 kernel/loader.rb
@@ -460,8 +460,8 @@ def debugger
if custom = Loader.debugger
custom.call
else
- require 'debugger'
- Debugger.start
+ require 'rubinius/debugger'
+ Rubinius::Debugger.start
end
end
end
View
418 lib/debugger.rb
@@ -1,416 +1,6 @@
-require 'readline'
-require 'debugger/frame'
-require 'debugger/commands'
-require 'debugger/breakpoint'
-require 'debugger/display'
-require 'compiler/iseq'
+require 'rubinius/debugger'
-#
-# The Rubinius reference debugger.
-#
-# This debugger is wired into the debugging APIs provided by Rubinius.
-# It serves as a simple, builtin debugger that others can use as
-# an example for how to build a better debugger.
-#
+warn "debugger.rb is deprecated, use rubinius/debugger and Rubinius::Debugger"
-class Debugger
- include Debugger::Display
-
- # Used to try and show the source for the kernel. Should
- # mostly work, but it's a hack.
- ROOT_DIR = File.expand_path(File.dirname(__FILE__) + "/..")
-
- # Create a new debugger object. The debugger starts up a thread
- # which is where the command line interface executes from. Other
- # threads that you wish to debug are told that their debugging
- # thread is the debugger thread. This is how the debugger is handed
- # control of execution.
- #
- def initialize
- @file_lines = Hash.new do |hash, path|
- if File.exists? path
- hash[path] = File.readlines(path)
- else
- ab_path = File.join(@root_dir, path)
- if File.exists? ab_path
- hash[path] = File.readlines(ab_path)
- else
- hash[path] = []
- end
- end
- end
-
- @thread = nil
- @frames = []
-
- @variables = {
- :show_ip => false,
- :show_bytecode => false,
- :highlight => false
- }
-
- @loaded_hook = proc { |file|
- check_defered_breakpoints
- }
-
- @added_hook = proc { |mod, name, exec|
- check_defered_breakpoints
- }
-
- # Use a few Rubinius specific hooks to trigger checking
- # for defered breakpoints.
-
- Rubinius::CodeLoader.loaded_hook.add @loaded_hook
- Rubinius.add_method_hook.add @added_hook
-
- @defered_breakpoints = []
-
- @user_variables = 0
-
- @breakpoints = []
-
- @history_path = File.expand_path("~/.rbx_debug")
-
- if File.exists?(@history_path)
- File.readlines(@history_path).each do |line|
- Readline::HISTORY << line.strip
- end
- @history_io = File.new(@history_path, "a")
- else
- @history_io = File.new(@history_path, "w")
- end
-
- @history_io.sync = true
-
- @root_dir = ROOT_DIR
- end
-
- attr_reader :variables, :current_frame, :breakpoints, :user_variables
- attr_reader :locations
-
- def self.global
- @global ||= new
- end
-
- def self.start
- global.start(1)
- end
-
- # This is simplest API point. This starts up the debugger in the caller
- # of this method to begin debugging.
- #
- def self.here
- global.start(1)
- end
-
- # Startup the debugger, skipping back +offset+ frames. This lets you start
- # the debugger straight into callers method.
- #
- def start(offset=0)
- spinup_thread
-
- # Feed info to the debugger thread!
- locs = Rubinius::VM.backtrace(offset + 1, true)
-
- method = Rubinius::CompiledMethod.of_sender
-
- bp = BreakPoint.new "<start>", method, 0, 0
- channel = Rubinius::Channel.new
-
- @local_channel.send Rubinius::Tuple[bp, Thread.current, channel, locs]
-
- # wait for the debugger to release us
- channel.receive
-
- Thread.current.set_debugger_thread @thread
- self
- end
-
- # Stop and wait for a debuggee thread to send us info about
- # stoping at a breakpoint.
- #
- def listen(step_into=false)
- while true
- if @channel
- if step_into
- @channel << :step
- else
- @channel << true
- end
- end
-
- # Wait for someone to stop
- bp, thr, chan, locs = @local_channel.receive
-
- # Uncache all frames since we stopped at a new place
- @frames = []
-
- @locations = locs
- @breakpoint = bp
- @debuggee_thread = thr
- @channel = chan
-
- @current_frame = frame(0)
-
- if bp
- # Only break out if the hit was valid
- break if bp.hit!(locs.first)
- else
- break
- end
- end
-
- puts
- info "Breakpoint: #{@current_frame.describe}"
- show_code
-
- if @variables[:show_bytecode]
- decode_one
- end
-
- end
-
- # Get a command from the user to run using readline
- #
- def accept_commands
- cmd = Readline.readline "debug> "
-
- if cmd.empty?
- cmd = @last_command
- else
- @last_command = cmd
- end
-
- command, args = cmd.strip.split(/\s+/, 2)
-
- runner = Command.commands.find { |k| k.match?(command) }
-
- if runner
- runner.new(self).run args
- else
- puts "Unrecognized command: #{command}"
- return
- end
-
- # Save it to the history.
- @history_io.puts cmd
- end
-
- def eval_code(args)
- obj = @current_frame.run(args)
-
- idx = @user_variables
- @user_variables += 1
-
- str = "$d#{idx}"
- Rubinius::Globals[str.to_sym] = obj
- puts "#{str} = #{obj.inspect}\n"
- end
-
- def frame(num)
- @frames[num] ||= Frame.new(self, num, @locations[num])
- end
-
- def set_frame(num)
- @current_frame = frame(num)
- end
-
- def each_frame(start=0)
- start = start.number if start.kind_of?(Frame)
-
- start.upto(@locations.size-1) do |idx|
- yield frame(idx)
- end
- end
-
- def set_breakpoint_method(descriptor, method, line=nil)
- exec = method.executable
-
- unless exec.kind_of?(Rubinius::CompiledMethod)
- error "Unsupported method type: #{exec.class}"
- return
- end
-
- if line
- ip = exec.first_ip_on_line(line)
-
- if ip == -1
- error "Unknown line '#{line}' in method '#{method.name}'"
- return
- end
- else
- line = exec.first_line
- ip = 0
- end
-
- bp = BreakPoint.new(descriptor, exec, ip, line)
- bp.activate
-
- @breakpoints << bp
-
- info "Set breakpoint #{@breakpoints.size}: #{bp.location}"
-
- return bp
- end
-
- def delete_breakpoint(i)
- bp = @breakpoints[i-1]
-
- unless bp
- error "Unknown breakpoint '#{i}'"
- return
- end
-
- bp.delete!
-
- @breakpoints[i-1] = nil
- end
-
- def add_defered_breakpoint(klass_name, which, name, line)
- dbp = DeferedBreakPoint.new(self, @current_frame, klass_name, which, name,
- line, @defered_breakpoints)
- @defered_breakpoints << dbp
- @breakpoints << dbp
- end
-
- def check_defered_breakpoints
- @defered_breakpoints.delete_if do |bp|
- bp.resolve!
- end
- end
-
- def send_between(exec, start, fin)
- ss = Rubinius::InstructionSet.opcodes_map[:send_stack]
- sm = Rubinius::InstructionSet.opcodes_map[:send_method]
- sb = Rubinius::InstructionSet.opcodes_map[:send_stack_with_block]
-
- iseq = exec.iseq
-
- fin = iseq.size if fin < 0
-
- i = start
- while i < fin
- op = iseq[i]
- case op
- when ss, sm, sb
- return exec.literals[iseq[i + 1]]
- else
- op = Rubinius::InstructionSet[op]
- i += (op.arg_count + 1)
- end
- end
-
- return nil
- end
-
- def show_code(line=@current_frame.line)
- path = @current_frame.method.active_path
-
- if str = @file_lines[path][line - 1]
- if @variables[:highlight]
- fin = @current_frame.method.first_ip_on_line(line + 1)
- name = send_between(@current_frame.method, @current_frame.ip, fin)
-
- if name
- str = str.gsub name.to_s, "\033[0;4m#{name}\033[0m"
- end
- end
- info "#{line}: #{str}"
- else
- show_bytecode(line)
- end
- end
-
- def decode_one
- ip = @current_frame.ip
-
- meth = @current_frame.method
- decoder = Rubinius::InstructionDecoder.new(meth.iseq)
- partial = decoder.decode_between(ip, ip+1)
-
- partial.each do |ins|
- op = ins.shift
-
- ins.each_index do |i|
- case op.args[i]
- when :literal
- ins[i] = meth.literals[ins[i]].inspect
- when :local
- if meth.local_names
- ins[i] = meth.local_names[ins[i]]
- end
- end
- end
-
- display "ip #{ip} = #{op.opcode} #{ins.join(', ')}"
- end
- end
-
- def show_bytecode(line=@current_frame.line)
- meth = @current_frame.method
- start = meth.first_ip_on_line(line)
- fin = meth.first_ip_on_line(line+1)
-
- if fin == -1
- fin = meth.iseq.size
- end
-
- section "Bytecode between #{start} and #{fin-1} for line #{line}"
-
- decoder = Rubinius::InstructionDecoder.new(meth.iseq)
- partial = decoder.decode_between(start, fin)
-
- ip = start
-
- partial.each do |ins|
- op = ins.shift
-
- ins.each_index do |i|
- case op.args[i]
- when :literal
- ins[i] = meth.literals[ins[i]].inspect
- when :local
- if meth.local_names
- ins[i] = meth.local_names[ins[i]]
- end
- end
- end
-
- info " %4d: #{op.opcode} #{ins.join(', ')}" % ip
-
- ip += (ins.size + 1)
- end
- end
-
- def spinup_thread
- return if @thread
-
- @local_channel = Rubinius::Channel.new
-
- @thread = Thread.new do
- begin
- listen
- rescue Exception => e
- e.render("Listening")
- break
- end
-
- while true
- begin
- accept_commands
- rescue Exception => e
- begin
- e.render "Error in debugger"
- rescue Exception => e2
- puts "Error rendering backtrace in debugger!"
- end
- end
- end
- end
-
- @thread.setup_control!(@local_channel)
- end
-
- private :spinup_thread
-
-end
+# To be deprecated in 1.2+
+Debugger = Rubinius::Debugger
View
416 lib/rubinius/debugger.rb
@@ -0,0 +1,416 @@
+require 'readline'
+require 'rubinius/debugger/frame'
+require 'rubinius/debugger/commands'
+require 'rubinius/debugger/breakpoint'
+require 'rubinius/debugger/display'
+require 'compiler/iseq'
+
+#
+# The Rubinius reference debugger.
+#
+# This debugger is wired into the debugging APIs provided by Rubinius.
+# It serves as a simple, builtin debugger that others can use as
+# an example for how to build a better debugger.
+#
+
+class Rubinius::Debugger
+ include Rubinius::Debugger::Display
+
+ # Used to try and show the source for the kernel. Should
+ # mostly work, but it's a hack.
+ ROOT_DIR = File.expand_path(File.dirname(__FILE__) + "/..")
+
+ # Create a new debugger object. The debugger starts up a thread
+ # which is where the command line interface executes from. Other
+ # threads that you wish to debug are told that their debugging
+ # thread is the debugger thread. This is how the debugger is handed
+ # control of execution.
+ #
+ def initialize
+ @file_lines = Hash.new do |hash, path|
+ if File.exists? path
+ hash[path] = File.readlines(path)
+ else
+ ab_path = File.join(@root_dir, path)
+ if File.exists? ab_path
+ hash[path] = File.readlines(ab_path)
+ else
+ hash[path] = []
+ end
+ end
+ end
+
+ @thread = nil
+ @frames = []
+
+ @variables = {
+ :show_ip => false,
+ :show_bytecode => false,
+ :highlight => false
+ }
+
+ @loaded_hook = proc { |file|
+ check_defered_breakpoints
+ }
+
+ @added_hook = proc { |mod, name, exec|
+ check_defered_breakpoints
+ }
+
+ # Use a few Rubinius specific hooks to trigger checking
+ # for defered breakpoints.
+
+ Rubinius::CodeLoader.loaded_hook.add @loaded_hook
+ Rubinius.add_method_hook.add @added_hook
+
+ @defered_breakpoints = []
+
+ @user_variables = 0
+
+ @breakpoints = []
+
+ @history_path = File.expand_path("~/.rbx_debug")
+
+ if File.exists?(@history_path)
+ File.readlines(@history_path).each do |line|
+ Readline::HISTORY << line.strip
+ end
+ @history_io = File.new(@history_path, "a")
+ else
+ @history_io = File.new(@history_path, "w")
+ end
+
+ @history_io.sync = true
+
+ @root_dir = ROOT_DIR
+ end
+
+ attr_reader :variables, :current_frame, :breakpoints, :user_variables
+ attr_reader :locations
+
+ def self.global
+ @global ||= new
+ end
+
+ def self.start
+ global.start(1)
+ end
+
+ # This is simplest API point. This starts up the debugger in the caller
+ # of this method to begin debugging.
+ #
+ def self.here
+ global.start(1)
+ end
+
+ # Startup the debugger, skipping back +offset+ frames. This lets you start
+ # the debugger straight into callers method.
+ #
+ def start(offset=0)
+ spinup_thread
+
+ # Feed info to the debugger thread!
+ locs = Rubinius::VM.backtrace(offset + 1, true)
+
+ method = Rubinius::CompiledMethod.of_sender
+
+ bp = BreakPoint.new "<start>", method, 0, 0
+ channel = Rubinius::Channel.new
+
+ @local_channel.send Rubinius::Tuple[bp, Thread.current, channel, locs]
+
+ # wait for the debugger to release us
+ channel.receive
+
+ Thread.current.set_debugger_thread @thread
+ self
+ end
+
+ # Stop and wait for a debuggee thread to send us info about
+ # stoping at a breakpoint.
+ #
+ def listen(step_into=false)
+ while true
+ if @channel
+ if step_into
+ @channel << :step
+ else
+ @channel << true
+ end
+ end
+
+ # Wait for someone to stop
+ bp, thr, chan, locs = @local_channel.receive
+
+ # Uncache all frames since we stopped at a new place
+ @frames = []
+
+ @locations = locs
+ @breakpoint = bp
+ @debuggee_thread = thr
+ @channel = chan
+
+ @current_frame = frame(0)
+
+ if bp
+ # Only break out if the hit was valid
+ break if bp.hit!(locs.first)
+ else
+ break
+ end
+ end
+
+ puts
+ info "Breakpoint: #{@current_frame.describe}"
+ show_code
+
+ if @variables[:show_bytecode]
+ decode_one
+ end
+
+ end
+
+ # Get a command from the user to run using readline
+ #
+ def accept_commands
+ cmd = Readline.readline "debug> "
+
+ if cmd.empty?
+ cmd = @last_command
+ else
+ @last_command = cmd
+ end
+
+ command, args = cmd.strip.split(/\s+/, 2)
+
+ runner = Command.commands.find { |k| k.match?(command) }
+
+ if runner
+ runner.new(self).run args
+ else
+ puts "Unrecognized command: #{command}"
+ return
+ end
+
+ # Save it to the history.
+ @history_io.puts cmd
+ end
+
+ def eval_code(args)
+ obj = @current_frame.run(args)
+
+ idx = @user_variables
+ @user_variables += 1
+
+ str = "$d#{idx}"
+ Rubinius::Globals[str.to_sym] = obj
+ puts "#{str} = #{obj.inspect}\n"
+ end
+
+ def frame(num)
+ @frames[num] ||= Frame.new(self, num, @locations[num])
+ end
+
+ def set_frame(num)
+ @current_frame = frame(num)
+ end
+
+ def each_frame(start=0)
+ start = start.number if start.kind_of?(Frame)
+
+ start.upto(@locations.size-1) do |idx|
+ yield frame(idx)
+ end
+ end
+
+ def set_breakpoint_method(descriptor, method, line=nil)
+ exec = method.executable
+
+ unless exec.kind_of?(Rubinius::CompiledMethod)
+ error "Unsupported method type: #{exec.class}"
+ return
+ end
+
+ if line
+ ip = exec.first_ip_on_line(line)
+
+ if ip == -1
+ error "Unknown line '#{line}' in method '#{method.name}'"
+ return
+ end
+ else
+ line = exec.first_line
+ ip = 0
+ end
+
+ bp = BreakPoint.new(descriptor, exec, ip, line)
+ bp.activate
+
+ @breakpoints << bp
+
+ info "Set breakpoint #{@breakpoints.size}: #{bp.location}"
+
+ return bp
+ end
+
+ def delete_breakpoint(i)
+ bp = @breakpoints[i-1]
+
+ unless bp
+ error "Unknown breakpoint '#{i}'"
+ return
+ end
+
+ bp.delete!
+
+ @breakpoints[i-1] = nil
+ end
+
+ def add_defered_breakpoint(klass_name, which, name, line)
+ dbp = DeferedBreakPoint.new(self, @current_frame, klass_name, which, name,
+ line, @defered_breakpoints)
+ @defered_breakpoints << dbp
+ @breakpoints << dbp
+ end
+
+ def check_defered_breakpoints
+ @defered_breakpoints.delete_if do |bp|
+ bp.resolve!
+ end
+ end
+
+ def send_between(exec, start, fin)
+ ss = Rubinius::InstructionSet.opcodes_map[:send_stack]
+ sm = Rubinius::InstructionSet.opcodes_map[:send_method]
+ sb = Rubinius::InstructionSet.opcodes_map[:send_stack_with_block]
+
+ iseq = exec.iseq
+
+ fin = iseq.size if fin < 0
+
+ i = start
+ while i < fin
+ op = iseq[i]
+ case op
+ when ss, sm, sb
+ return exec.literals[iseq[i + 1]]
+ else
+ op = Rubinius::InstructionSet[op]
+ i += (op.arg_count + 1)
+ end
+ end
+
+ return nil
+ end
+
+ def show_code(line=@current_frame.line)
+ path = @current_frame.method.active_path
+
+ if str = @file_lines[path][line - 1]
+ if @variables[:highlight]
+ fin = @current_frame.method.first_ip_on_line(line + 1)
+ name = send_between(@current_frame.method, @current_frame.ip, fin)
+
+ if name
+ str = str.gsub name.to_s, "\033[0;4m#{name}\033[0m"
+ end
+ end
+ info "#{line}: #{str}"
+ else
+ show_bytecode(line)
+ end
+ end
+
+ def decode_one
+ ip = @current_frame.ip
+
+ meth = @current_frame.method
+ decoder = Rubinius::InstructionDecoder.new(meth.iseq)
+ partial = decoder.decode_between(ip, ip+1)
+
+ partial.each do |ins|
+ op = ins.shift
+
+ ins.each_index do |i|
+ case op.args[i]
+ when :literal
+ ins[i] = meth.literals[ins[i]].inspect
+ when :local
+ if meth.local_names
+ ins[i] = meth.local_names[ins[i]]
+ end
+ end
+ end
+
+ display "ip #{ip} = #{op.opcode} #{ins.join(', ')}"
+ end
+ end
+
+ def show_bytecode(line=@current_frame.line)
+ meth = @current_frame.method
+ start = meth.first_ip_on_line(line)
+ fin = meth.first_ip_on_line(line+1)
+
+ if fin == -1
+ fin = meth.iseq.size
+ end
+
+ section "Bytecode between #{start} and #{fin-1} for line #{line}"
+
+ decoder = Rubinius::InstructionDecoder.new(meth.iseq)
+ partial = decoder.decode_between(start, fin)
+
+ ip = start
+
+ partial.each do |ins|
+ op = ins.shift
+
+ ins.each_index do |i|
+ case op.args[i]
+ when :literal
+ ins[i] = meth.literals[ins[i]].inspect
+ when :local
+ if meth.local_names
+ ins[i] = meth.local_names[ins[i]]
+ end
+ end
+ end
+
+ info " %4d: #{op.opcode} #{ins.join(', ')}" % ip
+
+ ip += (ins.size + 1)
+ end
+ end
+
+ def spinup_thread
+ return if @thread
+
+ @local_channel = Rubinius::Channel.new
+
+ @thread = Thread.new do
+ begin
+ listen
+ rescue Exception => e
+ e.render("Listening")
+ break
+ end
+
+ while true
+ begin
+ accept_commands
+ rescue Exception => e
+ begin
+ e.render "Error in debugger"
+ rescue Exception => e2
+ puts "Error rendering backtrace in debugger!"
+ end
+ end
+ end
+ end
+
+ @thread.setup_control!(@local_channel)
+ end
+
+ private :spinup_thread
+
+end
View
2  lib/debugger/breakpoint.rb → lib/rubinius/debugger/breakpoint.rb
@@ -1,4 +1,4 @@
-class Debugger
+class Rubinius::Debugger
class BreakPoint
def self.for_ip(exec, ip, name=:anon)
View
6 lib/debugger/commands.rb → lib/rubinius/debugger/commands.rb
@@ -1,6 +1,6 @@
-require 'debugger/display'
+require 'rubinius/debugger/display'
-class Debugger
+class Rubinius::Debugger
class CommandDescription
attr_accessor :klass, :patterns, :help, :ext_help
@@ -14,7 +14,7 @@ def name
end
class Command
- include Debugger::Display
+ include Rubinius::Debugger::Display
@commands = []
View
2  lib/debugger/display.rb → lib/rubinius/debugger/display.rb
@@ -1,4 +1,4 @@
-class Debugger
+class Rubinius::Debugger
module Display
def info(str)
puts "| #{str}"
View
2  lib/debugger/frame.rb → lib/rubinius/debugger/frame.rb
@@ -1,4 +1,4 @@
-class Debugger
+class Rubinius::Debugger
class Frame
def initialize(debugger, number, loc)
@debugger = debugger
View
0  lib/debugger/old/command.rb → lib/rubinius/debugger/old/command.rb
File renamed without changes
View
0  lib/debugger/old/debug_client.rb → lib/rubinius/debugger/old/debug_client.rb
File renamed without changes
View
0  lib/debugger/old/debug_server.rb → lib/rubinius/debugger/old/debug_server.rb
File renamed without changes
View
0  lib/debugger/old/debugger.rb → lib/rubinius/debugger/old/debugger.rb
File renamed without changes
View
0  lib/debugger/old/interface.rb → lib/rubinius/debugger/old/interface.rb
File renamed without changes
View
0  lib/debugger/old/output.rb → lib/rubinius/debugger/old/output.rb
File renamed without changes
View
0  lib/debugger/old/standard_commands.rb → lib/rubinius/debugger/old/standard_commands.rb
File renamed without changes
View
0  lib/debugger/old/vm_commands.rb → lib/rubinius/debugger/old/vm_commands.rb
File renamed without changes
View
20 preinstalled-gems/data/gems/ruby-debug-0.10.47/lib/ruby-debug.rb
@@ -1,4 +1,20 @@
-require 'debugger'
+require 'rubinius/debugger'
+
+module Debugger
+ def self.start(options=nil)
+ # a noop, started automatically when needed
+ @started = true
+ yield self if block_given?
+ end
+
+ def self.started?
+ @started
+ end
+
+ def self.stop
+ # noop
+ end
+end
module Kernel
@@ -6,7 +22,7 @@ module Kernel
#
# +steps+ is currently ignored.
def debugger(steps = 1)
- Debugger.global.start(1)
+ Rubinius::Debugger.global.start(1)
end
alias breakpoint debugger unless respond_to?(:breakpoint)
end
Please sign in to comment.
Something went wrong with that request. Please try again.