<commit_before>import struct
import sys
from .abstractcpu import Cpu, RegisterFile, Operand
from .abstractcpu import SymbolicPCException, InvalidPCException, Interruption
from .abstractcpu import instruction as abstract_instruction
from .register import Register
from ..smtlib import Operators, Expression, BitVecConstant
from ...utils.helpers import issymbolic
# from ..smtlib import *
from functools import wraps
from bitwise import *

from capstone import *
from capstone.arm import *

import logging
logger = logging.getLogger("CPU")

# map different instructions to a single impl here
OP_NAME_MAP = {
    'MOVW': 'MOV'
}

def HighBit(n):
    return Bit(n, 31)

def instruction(body):
    @wraps(body)
    def instruction_implementation(cpu, *args, **kwargs):
        ret = None

        should_execute = cpu.shouldExecuteConditional()

        if issymbolic(should_execute):
            i_size = cpu.address_bit_size / 8
            cpu.PC = Operators.ITEBV(cpu.address_bit_size, should_execute, cpu.PC-i_size,
                    cpu.PC)
            return

        if should_execute:
            ret = body(cpu, *args, **kwargs)

        if cpu.shouldCommitFlags():
            cpu.commitFlags()

        return ret

    return abstract_instruction(instruction_implementation)

class Armv7Operand(Operand):
    def __init__(self, cpu, op, **kwargs):
        super(Armv7Operand, self).__init__(cpu, op, **kwargs)

    @property
    def type(self):
        type_map = { ARM_OP_REG: 'register',
                     ARM_OP_MEM: 'memory',
                     ARM_OP_IMM: 'immediate'}

        return type_map[self.op.type]

    @property
    def size(self):
        assert self.type == 'register'
        if self.op.reg >= ARM_REG_D0 and self.op.reg <= ARM_REG_D31:
            return 64
        else:
            #FIXME check other types of operand sizes
            return 32

    def read(self, nbits=None, withCarry=False):
        carry = self.cpu.regfile.read('APSR_C')
        if self.type == 'register':
            value = self.cpu.regfile.read(self.reg)
            # XXX This can be an offset of 8, depending on ARM mode
            if self.reg in ('PC', 'R15'):
                value += 4
            if self.is_shifted():
                shift = self.op.shift
                value, carry = self.cpu._Shift(value, shift.type, shift.value, carry)
            if self.op.subtracted:
                value = -value
            if withCarry:
                return value, carry
            return value
        elif self.type == 'immediate':
            imm = self.op.imm
            if self.op.subtracted:
                imm = -imm
            if withCarry:
                return imm, self._getExpandImmCarry(carry)
            return imm

        elif self.type == 'memory':
            val = self.cpu.read_int(self.address(), nbits)
            if withCarry:
                return (val, carry)
            return val
        else:
            raise NotImplementedError("readOperand unknown type", self.op.type)

    def write(self, value, nbits=None):
        if self.type == 'register':
            self.cpu.regfile.write(self.reg, value)
        elif self.type == 'memory':
            raise NotImplementedError('need to impl arm store mem')
        else:
            raise NotImplementedError("writeOperand unknown type", self.op.type)

    def writeback(self, value):
        if self.type == 'register':
            self.write(value)
        elif self.type == 'memory':
            self.cpu.regfile.write(self.mem.base, value)
        else:
            raise NotImplementedError("writeback Operand unknown type", self.op.type)

    def is_shifted(self):
        return self.op.shift.type != ARM_SFT_INVALID

    def address(self):
        assert self.type == 'memory'
        addr = self.get_mem_base_addr() + self.get_mem_offset()
        return addr & Mask(self.cpu.address_bit_size)

    def get_mem_offset(self):
        assert self.type == 'memory'

        off = 0
        if self.mem.index is not None:
            idx = self.mem.scale * self.cpu.regfile.read(self.mem.index)
            carry = self.cpu.regfile.read('APSR_C')
            if self.is_shifted():
                shift = self.op.shift
                idx, carry = self.cpu._Shift(idx, shift.type, shift.value,  carry)
            off = idx
        else:
            off = self.mem.disp
        return -off if self.op.subtracted else off

    def get_mem_base_addr(self):
        assert self.type == 'memory'

        base = self.cpu.regfile.read(self.mem.base)

        # If pc is the base, we need to correct for the fact that the ARM
        # spec defines PC to point to the current insn + 8, which we are not
        # compliant with (we do current insn + 4)
        return base+4 if self.mem.base in ('PC', 'R15')  else base

    def _getExpandImmCarry(self, carryIn):
        '''Manually compute the carry bit produced by expanding an immediate
        operand (see ARMExpandImm_C)
        '''
        insn = struct.unpack('<I', self.cpu.instruction.bytes)[0]
        unrotated = insn & Mask(8)
        shift = Operators.EXTRACT(insn, 8, 4)
        _, carry = self.cpu._Shift(unrotated, ARM_SFT_ROR, 2*shift, carryIn)
        return carry

<commit_msg>Fix arm offset calculation (#152)<commit_after>import struct
import sys
from .abstractcpu import Cpu, RegisterFile, Operand
from .abstractcpu import SymbolicPCException, InvalidPCException, Interruption
from .abstractcpu import instruction as abstract_instruction
from .register import Register
from ..smtlib import Operators, Expression, BitVecConstant
from ...utils.helpers import issymbolic
# from ..smtlib import *
from functools import wraps
from bitwise import *

from capstone import *
from capstone.arm import *

import logging
logger = logging.getLogger("CPU")

# map different instructions to a single impl here
OP_NAME_MAP = {
    'MOVW': 'MOV'
}

def HighBit(n):
    return Bit(n, 31)

def instruction(body):
    @wraps(body)
    def instruction_implementation(cpu, *args, **kwargs):
        ret = None

        should_execute = cpu.shouldExecuteConditional()

        if issymbolic(should_execute):
            i_size = cpu.address_bit_size / 8
            cpu.PC = Operators.ITEBV(cpu.address_bit_size, should_execute, cpu.PC-i_size,
                    cpu.PC)
            return

        if should_execute:
            ret = body(cpu, *args, **kwargs)

        if cpu.shouldCommitFlags():
            cpu.commitFlags()

        return ret

    return abstract_instruction(instruction_implementation)

class Armv7Operand(Operand):
    def __init__(self, cpu, op, **kwargs):
        super(Armv7Operand, self).__init__(cpu, op, **kwargs)

    @property
    def type(self):
        type_map = { ARM_OP_REG: 'register',
                     ARM_OP_MEM: 'memory',
                     ARM_OP_IMM: 'immediate'}

        return type_map[self.op.type]

    @property
    def size(self):
        assert self.type == 'register'
        if self.op.reg >= ARM_REG_D0 and self.op.reg <= ARM_REG_D31:
            return 64
        else:
            #FIXME check other types of operand sizes
            return 32

    def read(self, nbits=None, withCarry=False):
        carry = self.cpu.regfile.read('APSR_C')
        if self.type == 'register':
            value = self.cpu.regfile.read(self.reg)
            # XXX This can be an offset of 8, depending on ARM mode
            if self.reg in ('PC', 'R15'):
                value += 4
            if self.is_shifted():
                shift = self.op.shift
                value, carry = self.cpu._Shift(value, shift.type, shift.value, carry)
            if self.op.subtracted:
                value = -value
            if withCarry:
                return value, carry
            return value
        elif self.type == 'immediate':
            imm = self.op.imm
            if self.op.subtracted:
                imm = -imm
            if withCarry:
                return imm, self._getExpandImmCarry(carry)
            return imm

        elif self.type == 'memory':
            val = self.cpu.read_int(self.address(), nbits)
            if withCarry:
                return (val, carry)
            return val
        else:
            raise NotImplementedError("readOperand unknown type", self.op.type)

    def write(self, value, nbits=None):
        if self.type == 'register':
            self.cpu.regfile.write(self.reg, value)
        elif self.type == 'memory':
            raise NotImplementedError('need to impl arm store mem')
        else:
            raise NotImplementedError("writeOperand unknown type", self.op.type)

    def writeback(self, value):
        if self.type == 'register':
            self.write(value)
        elif self.type == 'memory':
            self.cpu.regfile.write(self.mem.base, value)
        else:
            raise NotImplementedError("writeback Operand unknown type", self.op.type)

    def is_shifted(self):
        return self.op.shift.type != ARM_SFT_INVALID

    def address(self):
        assert self.type == 'memory'
        addr = self.get_mem_base_addr() + self.get_mem_offset()
        return addr & Mask(self.cpu.address_bit_size)

    def get_mem_offset(self):
        assert self.type == 'memory'

        off = 0
        if self.mem.index is not None:
            idx = self.mem.scale * self.cpu.regfile.read(self.mem.index)
            carry = self.cpu.regfile.read('APSR_C')
            if self.is_shifted():
                shift = self.op.shift
                idx, carry = self.cpu._Shift(idx, shift.type, shift.value,  carry)
            off = -idx if self.op.subtracted else idx
        else:
            off = self.mem.disp
        return off

    def get_mem_base_addr(self):
        assert self.type == 'memory'

        base = self.cpu.regfile.read(self.mem.base)

        # If pc is the base, we need to correct for the fact that the ARM
        # spec defines PC to point to the current insn + 8, which we are not
        # compliant with (we do current insn + 4)
        return base+4 if self.mem.base in ('PC', 'R15')  else base

    def _getExpandImmCarry(self, carryIn):
        '''Manually compute the carry bit produced by expanding an immediate
        operand (see ARMExpandImm_C)
        '''
        insn = struct.unpack('<I', self.cpu.instruction.bytes)[0]
        unrotated = insn & Mask(8)
        shift = Operators.EXTRACT(insn, 8, 4)
        _, carry = self.cpu._Shift(unrotated, ARM_SFT_ROR, 2*shift, carryIn)
        return carry


{'fraction_non_alphanumeric': 0.09832794983849516, 'fraction_numerical': 0.005415162454873646, 'mean_word_length': 2.055732946298984, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4300703', 'n_tokens_mistral': 3160, 'n_tokens_neox': 3046, 'n_words': 850}