Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 177 lines (154 sloc) 6.426 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
# Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
require_relative 'virtual'
class Trepan
  class CmdProcessor < VirtualCmdProcessor

    attr_accessor :stop_condition # String or nil. When not nil
                                   # this has to eval non-nil
                                   # in order to stop.
    attr_accessor :stop_events # Set or nil. If not nil, only
                                   # events in this set will be
                                   # considered for stopping. This is
                                   # like core.step_events (which
                                   # could be used instead), but it is
                                   # a set of event names rather than
                                   # a bitmask and it is intended to
                                   # be more temporarily changed via
                                   # "step>" or "step!" commands.
    attr_accessor :to_method
                                  
    # Does whatever needs to be done to set to continue program
    # execution.
    # FIXME: turn line_number into a condition.
    def continue
      @next_level = 32000 # I'm guessing the stack size can't
                               # ever reach this
      @next_thread = nil
      if @settings[:traceprint]
        @core.step_count = 1 # traceprint will avoid stopping
      else
        @core.step_count = -1 # No more event stepping
      end
      @leave_cmd_loop = true # Break out of the processor command loop.
    end

    # Does whatever setup needs to be done to set to ignore stepping
    # to the finish of the current method.
    def finish(level_count=0, opts={})
      step(0, opts)
      @next_level = @frame.stack_size - level_count
      @next_thread = Thread.current
      @stop_events = Set.new(%w(return leave yield))

      # Try high-speed (run-time-assisted) method
      @frame.trace_off = true # No more tracing in this frame
      @frame.return_stop = true # don't need to
    end

    # Does whatever needs to be done to set to do "step over" or ignore
    # stepping into methods called from this stack but step into any in
    # the same level. We do this by keeping track of the number of
    # stack frames and the current thread. Elsewhere in "skipping_step?"
    # we do the checking.
    def next(step_count=1, opts={})
      step(step_count, opts)
      @next_level = @top_frame.stack_size
      @next_thread = Thread.current
    end

    # Does whatever needs to be done to set to step program
    # execution.
    def step(step_count=1, opts={}, condition=nil)
      continue
      @core.step_count = step_count
      @different_pos = opts[:different_pos] if
        opts.keys.member?(:different_pos)
      @stop_condition = condition
      @stop_events = opts[:stop_events] if
        opts.keys.member?(:stop_events)
      @to_method = opts[:to_method]
    end

    def quit(cmd='quit')
      @next_level = 32000 # I'm guessing the stack size can't
                               # ever reach this
      @next_thread = nil
      @core.step_count = -1 # No more event stepping
      @leave_cmd_loop = true # Break out of the processor command loop.
      @settings[:autoirb] = false
      @cmdloop_prehooks.delete_by_name('autoirb')
      @commands['quit'].run([cmd])
    end

    def parse_next_step_suffix(step_cmd)
      opts = {}
      case step_cmd[-1..-1]
      when '-'
        opts[:different_pos] = false
      when '+'
        opts[:different_pos] = 'nostack'
      when '='
        opts[:different_pos] = true
      when '!'
        opts[:stop_events] = Set.new(%w(raise))
      when '<'
        opts[:stop_events] = Set.new(%w(c-return return))
      when '>'
        if step_cmd.size > 1 && step_cmd[-2..-2] == '<'
          opts[:stop_events] = Set.new(%w(c-call c-return call return))
        else
          opts[:stop_events] = Set.new(%w(c-call call))
        end
      end
      return opts
    end

    def running_initialize
      @stop_condition = nil
      @stop_events = nil
      @to_method = nil
    end

    def stepping_skip?

      return true if @core.step_count < 0

      if @settings[:'debugskip']
        msg "diff: #{@different_pos}, event : #{@event}, #{@stop_events.inspect}"
        msg "step_count : #{@core.step_count}"
        msg "next_level : #{@next_level}, ssize : #{@stack_size}"
        msg "next_thread : #{@next_thread}, thread: #{Thread.current}"
      end

      return true if
        !frame || (@next_level < @frame.stack_size &&
                   Thread.current == @next_thread && @event != 'raise')

      new_pos = [@frame.source_container, frame_line,
                 @stack_size, @current_thread, @event, @frame.pc_offset]

      skip_val = @stop_events && !@stop_events.member?(@event)

      # If the last stop was a breakpoint, don't stop again if we are at
      # the same location with a line event.
      skip_val ||= (@last_pos[4] == 'brkpt' &&
                    @event == 'line' &&
                    @frame.pc_offset == @last_pos[5])

      if @settings[:'debugskip']
        puts "skip: #{skip_val.inspect}, last: #{@last_pos}, new: #{new_pos}"
      end

      @last_pos[2] = new_pos[2] if 'nostack' == @different_pos
      unless skip_val
        condition_met =
          if @stop_condition
            puts 'stop_cond' if @settings[:'debugskip']
            debug_eval_no_errmsg(@stop_condition)
          elsif @to_method
            puts "method #{@frame.method} #{@to_method}" if
              @settings[:'debugskip']
            @frame.method == @to_method
          else
            puts 'uncond' if @settings[:'debugskip']
            true
          end
          
        msg("condition_met: #{condition_met}, last: #{@last_pos}, " +
             "new: #{new_pos}, different #{@different_pos.inspect}") if
          @settings[:'debugskip']
        skip_val = ((@last_pos[0..3] == new_pos[0..3] && @different_pos) ||
                    !condition_met)
      end

      @last_pos = new_pos if !@stop_events || @stop_events.member?(@event)

      unless skip_val
        # Set up the default values for the
        # next time we consider skipping.
        @different_pos = @settings[:different]
        @stop_events = nil
      end
      
      return skip_val
    end

  end
end
Something went wrong with that request. Please try again.