rubinius-debugger-2.2.1/0000755000175000017500000000000012641556127013545 5ustar aleealeerubinius-debugger-2.2.1/Rakefile0000644000175000017500000000003412641556127015207 0ustar aleealeerequire "bundler/gem_tasks" rubinius-debugger-2.2.1/lib/0000755000175000017500000000000012641556127014313 5ustar aleealeerubinius-debugger-2.2.1/lib/rubinius/0000755000175000017500000000000012641556127016153 5ustar aleealeerubinius-debugger-2.2.1/lib/rubinius/debugger.rb0000644000175000017500000002670412641556127020275 0ustar aleealeerequire 'readline' require 'rubinius/debugger/frame' require 'rubinius/debugger/commands' require 'rubinius/debugger/breakpoint' require 'rubinius/debugger/display' require 'rubinius/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 # Find the source for the kernel. ROOT_DIR = File.expand_path("../", Rubinius::KERNEL_PATH) # 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, :list_command_history => { :path => nil, :center_line => nil } } @loaded_hook = proc { |file| check_deferred_breakpoints } @added_hook = proc { |mod, name, exec| check_deferred_breakpoints } # Use a few Rubinius specific hooks to trigger checking # for deferred breakpoints. Rubinius::CodeLoader.loaded_hook.add @loaded_hook Rubinius.add_method_hook.add @added_hook @deferred_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::CompiledCode.of_sender bp = BreakPoint.new "", 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 if bp.hit!(locs.first) if bp.has_condition? break if @current_frame.run(bp.condition) else break end end else break end end puts info "Breakpoint: #{@current_frame.describe}" show_code eval_code(@breakpoint.commands) if @breakpoint && @breakpoint.has_commands? if @variables[:show_bytecode] decode_one end end # Get a command from the user to run using readline # def accept_commands command_list_code = [] cmd = Readline.readline "debug> " if cmd.nil? # ^D was entered cmd = "quit" elsif cmd.empty? cmd = @last_command else @last_command = cmd Readline::HISTORY << cmd end command, args = cmd.to_s.strip.split(/\s+/, 2) runner = Command.commands.find { |k| k.match?(command) } if runner if runner == Command::CommandsList bp_id = (args || @breakpoints.size).to_i if @breakpoints.empty? puts "No breakpoint set" return elsif bp_id > @breakpoints.size || bp_id < 1 puts "Invalid breakpoint number." return end puts "Type commands for breakpoint ##{bp_id}, one per line." puts "End with a line saying just 'END'." code = Readline.readline "> " while code != 'END' command_list_code << code code = Readline.readline "> " end args = { :bp_id => bp_id, :code => command_list_code.empty? ? nil : command_list_code.join(";") } end runner.new(self).run args else puts "Unrecognized command: #{command}" return end # Save it to the history. @history_io.puts cmd unless command_list_code.empty? command_list_code << "END" @history_io.puts command_list_code.join("\n") end end def eval_code(args, pretty = false) obj = @current_frame.run(args) idx = @user_variables @user_variables += 1 str = "$d#{idx}" Rubinius::Globals[str.to_sym] = obj if pretty require 'pp' puts "#{str} = #{obj.pretty_inspect}\n" else puts "#{str} = #{obj.inspect}\n" end 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, condition=nil, commands=nil, index=nil) exec = method.executable unless exec.kind_of?(Rubinius::CompiledCode) error "Unsupported method type: #{exec.class}" return end if line ip = exec.first_ip_on_line(line) if !ip 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, condition) bp.activate if index bp.set_commands(commands) @breakpoints[index] = bp info "Set breakpoint #{index+1}: #{bp.location}" else @breakpoints << bp info "Set breakpoint #{@breakpoints.size}: #{bp.location}" end 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_deferred_breakpoint(klass_name, which, name, line) dbp = DeferredBreakPoint.new(self, @current_frame, klass_name, which, name, line, @deferred_breakpoints) @deferred_breakpoints << dbp @breakpoints << dbp end def check_deferred_breakpoints @deferred_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 list_code_around_line(path, center_line, lines_to_show) lines_around = lines_to_show / 2 start_line = center_line - lines_around end_line = center_line + lines_around list_code_range(path, start_line, end_line, center_line) end def list_code_range(path, start_line, end_line, center_line) if !File.exists?(path) && !File.exists?(File.join(@root_dir, path)) error "Cannot find file #{path}" return end if start_line > @file_lines[path].size error "Line number #{@file_lines[path].size + 1} out of range: #{path} has #{@file_lines[path].size} lines." return end start_line = 1 if start_line < 1 end_line = @file_lines[path].size if end_line > @file_lines[path].size @variables[:list_command_history][:path] = path @variables[:list_command_history][:center_line] = center_line (start_line).upto(end_line) do |i| show_code(i, path) end end def show_code(line = @current_frame.line, path = @current_frame.method.active_path) if str = @file_lines[path][line - 1] if @variables[:highlight] if fin = @current_frame.method.first_ip_on_line(line + 1) if name = send_between(@current_frame.method, @current_frame.ip, fin) str = str.gsub name.to_s, "\033[0;4m#{name}\033[0m" end 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 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 rubinius-debugger-2.2.1/lib/rubinius/debugger/0000755000175000017500000000000012641556127017737 5ustar aleealeerubinius-debugger-2.2.1/lib/rubinius/debugger/frame.rb0000644000175000017500000000274012641556127021361 0ustar aleealeeclass Rubinius::Debugger class Frame def initialize(debugger, number, loc) @debugger = debugger @number = number @location = loc end attr_reader :number, :location def run(code) eval(code, binding) end def binding @binding ||= Binding.setup( @location.variables, @location.method, @location.constant_scope) end def method @location.method end def line @location.line end def ip @location.ip end def variables @location.variables end def local_variables method.local_names end def describe if method.required_args > 0 locals = [] 0.upto(method.required_args-1) do |arg| locals << method.local_names[arg].to_s end arg_str = locals.join(", ") else arg_str = "" end loc = @location if loc.is_block if arg_str.empty? recv = "{ } in #{loc.describe_receiver}#{loc.name}" else recv = "{|#{arg_str}| } in #{loc.describe_receiver}#{loc.name}" end else if arg_str.empty? recv = loc.describe else recv = "#{loc.describe}(#{arg_str})" end end str = "#{recv} at #{loc.method.active_path}:#{loc.line} (#{loc.ip})" if @debugger.variables[:show_ip] str << " (+#{loc.ip})" end str end end end rubinius-debugger-2.2.1/lib/rubinius/debugger/breakpoint.rb0000644000175000017500000000571112641556127022426 0ustar aleealeeclass Rubinius::Debugger class BreakPoint def self.for_ip(exec, ip, name=:anon) line = exec.line_from_ip(ip) BreakPoint.new(name, exec, ip, line) end def initialize(descriptor, method, ip, line, condition=nil) @descriptor = descriptor @method = method @ip = ip @line = line @for_step = false @paired_bp = nil @temp = false @commands = nil @condition = condition @set = false end attr_reader :method, :ip, :line, :paired_bp, :descriptor, :commands, :condition def location "#{@method.active_path}:#{@line} (+#{ip})" end def describe "#{descriptor} - #{location}" end def for_step!(scope) @temp = true @for_step = scope end def set_temp! @temp = true end def for_step? @for_step end def paired_with(bp) @paired_bp = bp end def activate @set = true @method.set_breakpoint @ip, self end def remove! return unless @set @set = false @method.clear_breakpoint(@ip) end def hit!(loc) return true unless @temp if @for_step return false unless loc.variables == @for_step end remove! @paired_bp.remove! if @paired_bp return true end def delete! remove! end def set_commands(commands) @commands = commands end def has_commands? !@commands.nil? end def set_condition(condition) @condition = condition end def has_condition? !@condition.nil? end end class DeferredBreakPoint def initialize(debugger, frame, klass, which, name, line=nil, list=nil) @debugger = debugger @frame = frame @klass_name = klass @which = which @name = name @line = line @list = list @commands = nil @condition = nil end attr_reader :condition, :commands def descriptor "#{@klass_name}#{@which}#{@name}" end def resolve! begin klass = @frame.run(@klass_name) rescue NameError return false end begin if @which == "#" method = klass.instance_method(@name) else method = klass.method(@name) end rescue NameError return false end @debugger.info "Resolved breakpoint for #{@klass_name}#{@which}#{@name}" index = @debugger.breakpoints.index(self) @debugger.set_breakpoint_method descriptor, method, @line, @condition, @commands, index return true end def describe "#{descriptor} - unknown location (deferred)" end def delete! if @list @list.delete self end end def set_commands(commands) @commands = commands end def has_commands? !@commands.nil? end def set_condition(condition) @condition = condition end def has_condition? !@condition.nil? end end end rubinius-debugger-2.2.1/lib/rubinius/debugger/display.rb0000644000175000017500000000057712641556127021742 0ustar aleealeeclass Rubinius::Debugger module Display def info(str) puts "| #{str}" end def display(str) puts "=> #{str}" end def crit(str) puts "[CRITICAL] #{str}" end def error(str) puts "* #{str}" end def section(str) puts "==== #{str} ====" end def ask(str) Readline.readline("| #{str}") end end end rubinius-debugger-2.2.1/lib/rubinius/debugger/commands.rb0000644000175000017500000004635712641556127022104 0ustar aleealeerequire 'rubinius/debugger/display' class Rubinius::Debugger class CommandDescription attr_accessor :klass, :patterns, :help, :ext_help def initialize(klass) @klass = klass end def name @klass.name end end class Command include Rubinius::Debugger::Display @commands = [] def self.commands @commands end def self.descriptor @descriptor ||= CommandDescription.new(self) end def self.pattern(*strs) Command.commands << self descriptor.patterns = strs end def self.help(str) descriptor.help = str end def self.ext_help(str) descriptor.ext_help = str end def self.match?(cmd) descriptor.patterns.include?(cmd) end def initialize(debugger) @debugger = debugger end def run_code(str) @debugger.current_frame.run(str) end def current_method @debugger.current_frame.method end def current_frame @debugger.current_frame end def variables @debugger.variables end def listen(step=false) @debugger.listen(step) end # ===== Commands ===== # # These classes are in the order they should appear in the help output. # As such, they're grouped by similar action. class Help < Command pattern "help", "h" help "Show information about debugger commands" def run(args) if args and !args.empty? klass = Command.commands.find { |k| k.match?(args.strip) } if klass des = klass.descriptor puts "Help for #{des.name}:" puts " Accessed using: #{des.patterns.join(', ')}" puts "\n#{des.help}." puts "\n#{des.ext_help}" if des.ext_help else puts "Unknown command: #{args}" end else Command.commands.each do |klass| des = klass.descriptor puts "%20s: #{des.help}" % des.patterns.join(', ') end end end end class SetBreakPoint < Command pattern "b", "break", "brk" help "Set a breakpoint at a point in a method" ext_help <<-HELP The breakpoint must be specified using the following notation: Klass[.#]method:line Thus, to set a breakpoint for the instance method pop in Array on line 33, use: Array#pop:33 To breakpoint on class method start of Debugger line 4, use: Debugger.start:4 Conditional breakpoints can be created in this way: if The breakpoint will be triggered only when the evaluation of the specified condition returns true. HELP # provide this method so it can be overriden for other languages wanting to use this debugger def match_method(method_identifier) /([A-Z]\w*(?:::[A-Z]\w*)*)([.#]|::)([a-zA-Z0-9_\[\]]+[!?=]?)(?:[:](\d+))?(\s+if\s+.*)?/.match(method_identifier) end def run(args, temp=false) m = match_method(args) unless m error "Unrecognized position: '#{args}'" return end klass_name = m[1] which = m[2] name = m[3] line = m[4] ? m[4].to_i : nil condition = m[5] ? m[5].sub(/\A\s+if\s+/, '') : nil begin klass = run_code(klass_name) rescue NameError error "Unable to find class/module: #{m[1]}" ask_deferred klass_name, which, name, line return end begin if which == "#" method = klass.instance_method(name) else method = klass.method(name) end rescue NameError error "Unable to find method '#{name}' in #{klass}" ask_deferred klass_name, which, name, line return end bp = @debugger.set_breakpoint_method args.strip, method, line, condition bp.set_temp! if temp return bp end def ask_deferred(klass_name, which, name, line) answer = ask "Would you like to defer this breakpoint to later? [y/n] " if answer.strip.downcase[0] == ?y @debugger.add_deferred_breakpoint(klass_name, which, name, line) info "Deferred breakpoint created." end end end class SetTempBreakPoint < SetBreakPoint pattern "tb", "tbreak", "tbrk" help "Set a temporary breakpoint" ext_help "Same as break, but the breakpoint is deleted when it is hit" def run(args) super args, true end end class DeleteBreakpoint < Command pattern "d", "del", "delete" help "Delete a breakpoint" ext_help "Specify the breakpoint by number, use 'info break' to see the numbers" def run(args) if !args or args.empty? error "Please specify which breakpoint by number" return end begin i = Integer(args.strip) rescue ArgumentError error "'#{args}' is not a number" return end @debugger.delete_breakpoint(i) end end class Next < Command pattern "n", "next" help "Move to the next line or conditional branch" ext_help <<-HELP Attempt to continue execution and stop at the next line. If there is a conditional branch between the current position and the next line, execution is stopped within the conditional branch instead. The optional argument is a number which specifies how many lines to attempt to skip past before stopping execution. If the current line is the last in a method, execution is stopped at the current position of the caller. HELP def run(args) if !args or args.empty? step = 1 else step = args.to_i end if step <= 0 error "Invalid step count - #{step}" return end step_over_by(step) @debugger.listen end def step_over_by(step) f = current_frame ip = -1 exec = f.method possible_line = f.line + step fin_ip = exec.first_ip_on_line possible_line, f.ip if !fin_ip return step_to_parent end set_breakpoints_between(exec, f.ip, fin_ip) end def step_to_parent f = @debugger.frame(current_frame.number + 1) unless f info "Unable to find frame to step to next" return end exec = f.method ip = f.ip bp = BreakPoint.for_ip(exec, ip) bp.for_step!(f.variables) bp.activate return bp end def set_breakpoints_between(exec, start_ip, fin_ip) ips = goto_between(exec, start_ip, fin_ip) if ips.kind_of? Fixnum ip = ips else one, two = ips bp1 = BreakPoint.for_ip(exec, one) bp2 = BreakPoint.for_ip(exec, two) bp1.paired_with(bp2) bp2.paired_with(bp1) bp1.for_step!(current_frame.variables) bp2.for_step!(current_frame.variables) bp1.activate bp2.activate return bp1 end if ip == -1 error "No place to step to" return nil end bp = BreakPoint.for_ip(exec, ip) bp.for_step!(current_frame.variables) bp.activate return bp end def next_interesting(exec, ip) pop = Rubinius::InstructionSet.opcodes_map[:pop] if exec.iseq[ip] == pop return ip + 1 end return ip end def goto_between(exec, start, fin) goto = Rubinius::InstructionSet.opcodes_map[:goto] git = Rubinius::InstructionSet.opcodes_map[:goto_if_true] gif = Rubinius::InstructionSet.opcodes_map[:goto_if_false] iseq = exec.iseq i = start while i < fin op = iseq[i] case op when goto return next_interesting(exec, iseq[i + 1]) # goto target when git, gif return [next_interesting(exec, iseq[i + 1]), next_interesting(exec, i + 2)] # target and next ip else op = Rubinius::InstructionSet[op] i += (op.arg_count + 1) end end return next_interesting(exec, fin) end end class StepInto < Next pattern "s", "step" help "Step into next method call or to next line" ext_help <<-HELP Behaves like next, but if there is a method call on the current line, execution is stopped in the called method. HELP def run(args) max = step_over_by(1) listen(true) # We remove the max position breakpoint no matter what max.remove! if max end end class NextInstruction < Next pattern "ni", "nexti" help "Move to the next bytecode instruction" ext_help <<-HELP Continue but stop execution at the next bytecode instruction. Does not step into send instructions. HELP def run(args) if args and !args.empty? step = args.to_i else step = 1 end exec = current_method insn = Rubinius::InstructionSet[exec.iseq[current_frame.ip]] next_ip = current_frame.ip + insn.width if next_ip >= exec.iseq.size step_to_parent elsif is_a_goto(exec, current_frame.ip) set_breakpoints_between(exec, current_frame.ip, next_ip) else line = exec.line_from_ip(next_ip) bp = BreakPoint.for_ip(exec, next_ip) bp.for_step!(current_frame.variables) bp.activate end listen end def is_a_goto(exec, ip) goto = Rubinius::InstructionSet.opcodes_map[:goto] git = Rubinius::InstructionSet.opcodes_map[:goto_if_true] gif = Rubinius::InstructionSet.opcodes_map[:goto_if_false] i = exec.iseq[ip] case i when goto, git, gif return true end return false end end class SetFrame < Command pattern "f", "frame" help "Make a specific frame in the call stack the current frame" ext_help <<-HELP The argument must be a number corrisponding to the frame numbers reported by 'bt'. The frame specified is made the current frame. HELP def run(args) unless m = /(\d+)/.match(args) error "Invalid frame number: #{args}" return end num = m[1].to_i if num >= @debugger.locations.size error "Frame #{num} too big" return end @debugger.set_frame(num) info current_frame.describe @debugger.show_code end end class Continue < Command pattern "c", "cont", "continue" help "Continue running the target thread" ext_help <<-HELP Continue execution until another breakpoint is hit. HELP def run(args) listen end end class Backtrace < Command pattern "bt", "backtrace" help "Show the current call stack" ext_help <<-HELP Show the call stack as a simple list. Passing "-v" will also show the values of all locals variables in each frame. HELP def run(args) verbose = (args =~ /-v/) if m = /(\d+)/.match(args) count = m[1].to_i else count = nil end info "Backtrace:" @debugger.each_frame(current_frame) do |frame| return if count and frame.number >= count info "%4d %s" % [frame.number, frame.describe] if verbose frame.local_variables.each do |local| info " #{local} = #{frame.run(local.to_s).inspect}" end end end end end class EvalCode < Command pattern "p", "eval" help "Run code in the current context" ext_help <<-HELP Run code in the context of the current frame. The value of the expression is stored into a global variable so it may be used again easily. The name of the global variable is printed next to the inspect output of the value. HELP def run(args) @debugger.eval_code(args) end end class PrettyPrintEvalCode < Command pattern "pp" help "Run code in the current context" ext_help <<-HELP Run code in the context of the current frame. Like 'eval', but pretty prints the result with 'pp'. HELP def run(args) @debugger.eval_code(args, true) end end class Disassemble < Command pattern "dis", "disassemble" help "Show the bytecode for the current line or method" ext_help <<-HELP Disassemble bytecode for the current method. By default, the bytecode for the current line is disassembled only. If the argument is 'all', the entire method is shown as bytecode. HELP def run(args) if args and args.strip == "all" section "Bytecode for #{current_frame.method.name}" puts current_method.decode else @debugger.show_bytecode end end end class ShowInfo < Command pattern "i", "info" help "Show information about things" ext_help <<-HELP Subcommands are: break, breakpoints, bp: List all breakpoints HELP def run(args) if args case args.strip when "break", "breakpoints", "bp" section "Breakpoints" if @debugger.breakpoints.empty? info "No breakpoints set" end @debugger.breakpoints.each_with_index do |bp, i| if bp info "%3d: %s" % [i+1, bp.describe] if bp.has_commands? info " #{bp.commands}" end if bp.has_condition? info " stop only if #{bp.condition}" end end end else error "Unknown info: '#{args}'" end else error "No info subcommand" end end end class SetVariable < Command pattern "set" help "Set a debugger config variable" ext_help <<-HELP Set a debugger configuration variable. Use 'show' to see all variables. HELP def run(args) var, val = args.split(/\s+/, 2) if val case val.strip when "true", "on", "yes", "" val = true when "false", "off", "no" val = false when "nil" val = nil when /\d+/ val = val.to_i end else val = true end info "Set '#{var}' = #{val.inspect}" @debugger.variables[var.to_sym] = val end end class ShowVariable < Command pattern "show" help "Display the value of a variable or variables" ext_help <<-HELP Show debugger variables and user created variables. By default, shows all variables. The optional argument is which variable specificly to show the value of. HELP def run(args) if !args or args.strip.empty? variables.each do |name, val| info "var '#{name}' = #{val.inspect}" end if @debugger.user_variables > 0 section "User variables" (0...@debugger.user_variables).each do |i| str = "$d#{i}" val = Rubinius::Globals[str.to_sym] info "var #{str} = #{val.inspect}" end end else var = args.strip.to_sym if variables.key?(var) info "var '#{var}' = #{variables[var].inspect}" else error "No variable set named '#{var}'" end end end end class Quit < Command pattern "quit", "q", "exit", "ex" help "Quit the debugger" ext_help <<-HELP Quits your current session and shuts down the complete process HELP def run(args) Process.exit!(1) end end class CommandsList < Command pattern "commands", "command" help "execute code every time breakpoint is reached" ext_help <<-HELP Set commands to be executed when a breakpoint is hit. Give breakpoint number as argument after "commands". With no argument, the targeted breakpoint is the last one set. The commands themselves follow starting on the next line. Type a line containing "end" to indicate the end of them. Give "silent" as the first line to make the breakpoint silent; then no output is printed when it is hit, except what the commands print. HELP def run(args) bp = @debugger.breakpoints[args[:bp_id] - 1] bp.set_commands(args[:code]) end end class Condition < Command pattern "condition", "cond" help "New condition expression on breakpoint N" ext_help <<-HELP Specify breakpoint number N to break only if COND is true. Usage is `condition N COND', where N is an integer and COND is an expression to be evaluated whenever breakpoint N is reached. HELP def run(args) bp_id, condition = args.split(/\s+/, 2) bp_id = bp_id.to_i if @debugger.breakpoints.empty? error "No breakpoint set" return elsif bp_id > @debugger.breakpoints.size || bp_id < 1 error "Invalid breakpoint number." return end bp = @debugger.breakpoints[bp_id - 1] bp.set_condition(condition) end end class ListCode < Command pattern "l", "list" help "List code" ext_help <<-HELP List specified function or line. With no argument, lists ten more lines after or around previous listing. "list -" lists the ten lines before a previous ten-line listing. One argument specifies a line, and ten lines are listed around that line. Two arguments with comma between specify starting and ending lines to list. Lines can be specified in these ways: LINENUM, to list around that line in current file, FILE:LINENUM, to list around that line in that file, HELP def run(args) path = nil line = nil lines_around = 10 if args =~ /^[\w#{File::Separator}]+(\.rb)?:\d+$/ path, line = args.split(':') line = line.to_i elsif args.nil? line = if @debugger.variables[:list_command_history][:center_line] @debugger.variables[:list_command_history][:center_line] + 1 + lines_around else @debugger.current_frame.line.to_i end path = @debugger.variables[:list_command_history][:path] || @debugger.current_frame.method.active_path elsif args == "-" if @debugger.variables[:list_command_history][:center_line].nil? || @debugger.variables[:list_command_history][:path].nil? return else line = @debugger.variables[:list_command_history][:center_line] - lines_around path = @debugger.variables[:list_command_history][:path] end elsif args =~ /^\d+$/ line = args.to_i path = @debugger.current_frame.method.active_path elsif match = /^(\d+),(\d+)$/.match(args) start_line = match[1].to_i end_line = match[2].to_i path = @debugger.current_frame.method.active_path @debugger.list_code_range(path, start_line, end_line, end_line) return else error 'Invalid args for list' return end @debugger.list_code_around_line(path, line, lines_around) end end end end rubinius-debugger-2.2.1/lib/rubinius/debugger/version.rb0000644000175000017500000000010212641556127021742 0ustar aleealeemodule Rubinius module Debugger VERSION = "2.2.1" end end rubinius-debugger-2.2.1/.gitignore0000644000175000017500000000023212641556127015532 0ustar aleealee*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp rubinius-debugger-2.2.1/README.md0000644000175000017500000000102012641556127015015 0ustar aleealee# Rubinius::Debugger TODO: Write a gem description ## Installation Add this line to your application's Gemfile: gem 'rubinius-debugger' And then execute: $ bundle Or install it yourself as: $ gem install rubinius-debugger ## Usage TODO: Write usage instructions here ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request rubinius-debugger-2.2.1/LICENSE0000644000175000017500000000267512641556127014564 0ustar aleealeeCopyright (c) 2013, Brian Shirai All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the library nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. rubinius-debugger-2.2.1/rubinius-debugger.gemspec0000644000175000017500000000143312641556127020535 0ustar aleealee# coding: utf-8 require './lib/rubinius/debugger/version' Gem::Specification.new do |spec| spec.name = "rubinius-debugger" spec.version = Rubinius::Debugger::VERSION spec.authors = ["Brian Shirai"] spec.email = ["brixen@gmail.com"] spec.description = %q{Rubinius debugger.} spec.summary = %q{Rubinius debugger.} spec.homepage = "https://github.com/rubinius/rubinius-debugger" spec.license = "BSD" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake", "~> 10.0" end rubinius-debugger-2.2.1/Gemfile0000644000175000017500000000014612641556127015041 0ustar aleealeesource 'https://rubygems.org' # Specify your gem's dependencies in rubinius-debugger.gemspec gemspec rubinius-debugger-2.2.1/metadata.yml0000644000175000017500000000362612641556127016057 0ustar aleealee--- !ruby/object:Gem::Specification name: rubinius-debugger version: !ruby/object:Gem::Version version: 2.2.1 platform: ruby authors: - Brian Shirai autorequire: bindir: bin cert_chain: [] date: 2015-02-03 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.3' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.3' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '10.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '10.0' description: Rubinius debugger. email: - brixen@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - Gemfile - LICENSE - README.md - Rakefile - lib/rubinius/debugger.rb - lib/rubinius/debugger/breakpoint.rb - lib/rubinius/debugger/commands.rb - lib/rubinius/debugger/display.rb - lib/rubinius/debugger/frame.rb - lib/rubinius/debugger/version.rb - rubinius-debugger.gemspec homepage: https://github.com/rubinius/rubinius-debugger licenses: - BSD metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.5 signing_key: specification_version: 4 summary: Rubinius debugger. test_files: [] has_rdoc: