Example #1
0
    def _pick_loopi_iterations(self, max_iters: int, op_type: OperandType,
                               model: Model) -> Optional[IterCount]:
        '''Pick the number of iterations for a LOOPI loop

        max_iters is the maximum number of iterations possible, given how much
        fuel we have left.

        Returns the encoded and decoded number of iterations.

        '''

        assert isinstance(op_type, ImmOperandType)
        iters_range = op_type.get_op_val_range(model.pc)
        assert iters_range is not None
        iters_lo, iters_hi = iters_range

        # Constrain iters_hi if the max-loop-iters configuration value was set.
        if self.cfg_max_iters is not None:
            iters_hi = min(iters_hi, self.cfg_max_iters)
            if iters_hi < iters_lo:
                return None

        # Very occasionally, generate iters_hi iterations (the maximum number
        # representable) if we've got fuel for it. We don't do this often,
        # because the instruction sequence will end up just testing loop
        # handling and be very inefficient for testing anything else.
        if max_iters >= iters_hi and random.random() < 0.01:
            enc_val = op_type.op_val_to_enc_val(iters_hi, model.pc)
            # This should never fail, because iters_hi was encodable.
            assert enc_val is not None
            return (enc_val, iters_hi, None)

        # The rest of the time, we don't usually (95%) generate more than 3
        # iterations (because the instruction sequences are rather
        # repetitive!). Also, don't generate 0 iterations here, even though
        # it's encodable. That causes an error, so we'll do that in a separate
        # generator.
        if random.random() < 0.95:
            tgt_max_iters = min(max_iters, 3)
        else:
            tgt_max_iters = 10000

        ub = min(iters_hi, max_iters, tgt_max_iters)
        lb = max(iters_lo, 1)

        if ub < lb:
            return None

        # Otherwise, pick a value uniformly in [iters_lo, iters_hi]. No need
        # for clever weighting: in the usual case, there are just 3
        # possibilities!
        num_iters = random.randint(lb, ub)
        enc_val = op_type.op_val_to_enc_val(num_iters, model.pc)
        # This should never fail: the choice should have been in the encodable
        # range.
        assert enc_val is not None
        return (enc_val, num_iters, None)
Example #2
0
    def pick_operand_value(self, op_type: OperandType) -> Optional[int]:
        '''Pick a random value for an operand

        The result will always be non-negative: if the operand is a signed
        immediate, this is encoded as 2s complement.

        '''
        if isinstance(op_type, RegOperandType):
            return self.pick_reg_operand_value(op_type)

        op_rng = op_type.get_op_val_range(self.pc)
        if op_rng is None:
            # If we don't know the width, the only immediate that we *know*
            # is going to be valid is 0.
            return 0

        if isinstance(op_type, ImmOperandType):
            shift = op_type.shift
        else:
            shift = 0

        align = 1 << shift

        lo, hi = op_rng
        sh_lo = (lo + align - 1) // align
        sh_hi = hi // align

        op_val = random.randint(sh_lo, sh_hi) << shift
        return op_type.op_val_to_enc_val(op_val, self.pc)
Example #3
0
    def _pick_loopi_iterations(self, op_type: OperandType, pc: int) -> int:
        # Like Loop._pick_loopi_iterations but simpler because it doesn't try
        # to weight towards small counts.
        assert isinstance(op_type, ImmOperandType)
        iters_range = op_type.get_op_val_range(pc)
        assert iters_range is not None
        iters_lo, iters_hi = iters_range
        assert 1 <= iters_hi
        num_iters = random.randint(max(iters_lo, 1), iters_hi)

        enc_val = op_type.op_val_to_enc_val(num_iters, pc)
        assert enc_val is not None
        return enc_val
Example #4
0
    def pick_operand_value(self, op_type: OperandType) -> Optional[int]:
        '''Pick a random value for an operand

        The result will always be non-negative: if the operand is a signed
        immediate, this is encoded as 2s complement.

        '''
        if isinstance(op_type, RegOperandType):
            return self.pick_reg_operand_value(op_type)

        op_rng = op_type.get_op_val_range(self.pc)
        if op_rng is None:
            # If we don't know the width, the only immediate that we *know*
            # is going to be valid is 0.
            return 0

        lo, hi = op_rng
        op_val = random.randrange(lo, hi + 1)
        return op_type.op_val_to_enc_val(op_val, self.pc)