From 7dd08799180501315580f827641a6d124e5ef75b Mon Sep 17 00:00:00 2001 From: feliam Date: Fri, 24 Mar 2017 14:44:24 -0300 Subject: [PATCH] Dev arm regfile refactor (#57) * RegisterFile refactor everywhere * Update arm_rf tests * Refactor Operand in both x86 and arm * Add APSR support (#53) * Add APSR support * #issuecomment-284826572 * APSR tests * cspr to aspr * RegisterFile refactor everywhere * Update arm_rf tests * Refactor Operand in both x86 and arm * Rebased and NotImplementedError fix * ARM register initialization compressed * Fix merging bugs * Assimilate PR comments * Assimilate PR comments2 * The new style. future is now * WIP * Improve quick start ,add asciinema (#58) * Towards a helloworld world * Rm requirements.txt (#56) * Print workspace dir by default (#55) * Print workspace dir by default * Change initial cli output * refactor or or or * WIP * Add arm rf testcase * ARM aliases fix * debug print removed * fix tests * Remove unicorn script from travis build (#64) * remove unicorn script from travis build * remove unicorn script entirely * Rename test -> tests (#66) * rename test -> tests * re-add ignored tests * Switch instructions to prefer virtualenv (#65) * switch instructions to prefer virtualenv * document use of virtualenvwrapper * Make cpuid more forgiving (#67) * Make cpuid more forgiving * error() to warning() * Add CPUID EAX=0xd ECX=0,1 * Let logger handle the format string iff needed * to hex * Rm unused files (#76) * Move state into own file (#75) * Move State from executor.py * Fix import * relative import * Rm unnecessary code (#80) * Add example crackme (#77) * add example crackme * make filename and directory structure more accurate * Fix state.branches (#74) * init * rm old code pretty sure it's wrong * Clean * rm * Rename record_fork, move to ConcretizeRegister exception handler It doesn't need to be in fork() because it's only relevant for when we fork due to PC. * Add test for record_branches * Add back record_branches which got removed in rebase Rebase went oddly because State got moved to a new file * unnecesary tuple() * necesary tuple * remove unnecessary keys() * Use OrderedDict (#84) It can be useful to know elements in `branches` towards the end are more recently discovered branches * arm: Fix broken dynamic APSR (#78) * Refactor Register (#82) * Fix register read bug If we store a BitVec, we do NOT want to return bool() of it, which returns True, which is totally incorrect. We do however, want to return a symbolic Bool of it, if it is a 1 bit register (flag). * Improve * Raise error * Fix register tests Changed the interfaces: - removed nbits param (never used) - no longer raise AssertionError when overflowing a flag reg, just truncate - rename test funcs to be more descriptive * rm unused import * Add symbolic tests * Rm no longer applicable test * Add docs (#61) * Add sphinx-quickstart generated docs * Add api.rst * Edit index.rst * Add autodocumenting Manticore class * Update Manticore docstring * Doc verbosity * Doc hook and add_hook * More docs * Add Sphinx dev dep For building docs * RegisterFile refactor everywhere * Update arm_rf tests * Refactor Operand in both x86 and arm * RegisterFile refactor everywhere * Refactor Operand in both x86 and arm * Rebased and NotImplementedError fix * ARM register initialization compressed * Fix merging bugs * Assimilate PR comments * Assimilate PR comments2 * The new style. future is now * WIP * Towards a helloworld world * refactor or or or * WIP * Add arm rf testcase * ARM aliases fix * debug print removed * fix tests * unnecesary tuple() * necesary tuple * remove unnecessary keys() * rebased * Remove test * https://github.com/trailofbits/manticore/pull/57#pullrequestreview-27971778 * https://github.com/trailofbits/manticore/pull/57#discussion_r107820815, https://github.com/trailofbits/manticore/pull/57#discussion_r107820331 * https://github.com/trailofbits/manticore/pull/57#discussion_r107821090 * https://github.com/trailofbits/manticore/pull/57#discussion_r107821066 * https://github.com/trailofbits/manticore/pull/57#discussion_r107821919 * OOps search and replace * (invalid) -> None * The (invalid) -> None * None vs. invalid * In armpy we know that STACK is SP so lets try to eliminate cpu.STACK in favor of x.SP * remove ugly hex * Removed redundant import and comment --- manticore/core/cpu/abstractcpu.py | 109 +++-- manticore/core/cpu/arm.py | 374 +++++------------ manticore/core/cpu/x86.py | 47 +-- manticore/models/linux.py | 20 +- tests/test_armv7cpu.py | 677 +++++++++++++++--------------- tests/test_armv7rf.py | 81 ++-- 6 files changed, 559 insertions(+), 749 deletions(-) diff --git a/manticore/core/cpu/abstractcpu.py b/manticore/core/cpu/abstractcpu.py index dc00713..bcc16f3 100644 --- a/manticore/core/cpu/abstractcpu.py +++ b/manticore/core/cpu/abstractcpu.py @@ -26,19 +26,16 @@ MU = { SANE_SIZES = {8, 16, 32, 64, 80, 128, 256} # This encapsulates how to acccess operands (regs/mem/immediates) for differents cpus class Operand(object): - __metaclass__ = ABCMeta - def _reg_name(self, reg_id): - return reg_id class MemSpec(object): + ''' Auxiliary class wraps capstone operand 'mem' attribute. This will return register names instead of Ids ''' def __init__(self, parent): self.parent = parent segment = property( lambda self: self.parent._reg_name(self.parent.op.mem.segment) ) base = property( lambda self: self.parent._reg_name(self.parent.op.mem.base) ) index = property( lambda self: self.parent._reg_name(self.parent.op.mem.index) ) - scale = property( lambda self: self.parent._reg_name(self.parent.op.mem.scale) ) - disp = property( lambda self: self.parent._reg_name(self.parent.op.mem.disp) ) - + scale = property( lambda self: self.parent.op.mem.scale ) + disp = property( lambda self: self.parent.op.mem.disp ) def __init__(self, cpu, op, **kwargs): ''' @@ -50,87 +47,84 @@ class Operand(object): @param cpu: A Cpu oinstance @param op: a Capstone operand (eew) ''' - self.cpu=cpu - self.op=op - if op.type == X86_OP_MEM: - self.mem = self.__class__.MemSpec(self) + assert isinstance(cpu, Cpu) + assert isinstance(op, (X86Op, ArmOp)) + self.cpu = cpu + self.op = op + self.mem = Operand.MemSpec(self) + + def _reg_name(self, reg_id): + ''' Translates a capstone register ID into the register name ''' + cs_reg_name = self.cpu.instruction.reg_name(reg_id) + if cs_reg_name is None or cs_reg_name.lower() == '(invalid)': + return None + return self.cpu._regfile._alias(cs_reg_name.upper()) def __getattr__(self, name): return getattr(self.op, name) - @abstractmethod + @property + def size(self): + ''' Return bit size of operand ''' + raise NotImplementedError + def address(self): ''' On a memory operand it returns the effective address ''' - pass + raise NotImplementedError - @abstractmethod def read(self): ''' It reads the operand value from the registers or memory ''' - pass + raise NotImplementedError - @abstractmethod def write(self, value): ''' It writes the value ofspecific type to the registers or memory ''' - pass + raise NotImplementedError # Basic register file structure not actully need to abstract as it's used only from the cpu implementation class RegisterFile(object): - def __init__(self, aliases=None): if aliases is None: aliases = {} self._aliases = aliases - ''''dict mapping from alias register name ('PC') to actual register name - ('RSP'), which can be passed into reg_id() - ''' + ''''dict mapping from alias register name ('PC') to actual register name ('RIP') ''' + + def _alias(self, register): + '''Get register canonical alias. ex. PC->RIP or PC->R15 ''' + return self._aliases.get(register, register) #@abstractmethod - def write(self, reg_id, value): - ''' Write value to the register reg_id - @param reg_id: a register id. Must be listed on all_registers + def write(self, register, value): + ''' Write value to the specified register + @param register: a register id. Must be listed on all_registers @param value: a value of the expected type @return the value actually written to the register ''' pass #@abstractmethod - def read(self, reg_id): - ''' Read value from the register identified by reg_id - @param reg_id: a register id. Must be listed on all_registers + def read(self, register): + ''' Read value from specified register + @param register: a register name. Must be listed on all_registers @return the register value ''' pass - #@abstractmethod - def reg_name(self, reg_id): - ''' Gives a string representation (name) of a register (ID->name) - @param reg_id: a register ID - ''' - pass - - #@abstractmethod - def reg_id(self, reg_name): - ''' Gives the register ID for a string representation of a register (name->ID) - @param reg_name: a string representation of reg_id register''' - pass - @property def all_registers(self): ''' Lists all possible register names (Including aliases) ''' - pass + return tuple(self._aliases) @property def canonical_registers(self): ''' List the minimal most beautiful set of registers needed ''' pass - def __contains__(self, reg_id): + def __contains__(self, register): ''' Check for register validity - @param reg_id: a register ID + @param register: a register name ''' - return reg_id in self.all_registers - + return self._alias(register) in self.all_registers ############################################################################ # Abstract cpu encapsulating common cpu methods used by models and executor. class Cpu(object): @@ -192,43 +186,36 @@ class Cpu(object): return self._regfile.all_registers #this operates on names - def write_register(self, name, value): + def write_register(self, register, value): ''' A convenient method to write a register by name (this accepts alias) - @param name a register name as listed in all_registers + @param register a register name as listed in all_registers @param value a value @return It will return the written value possibly croped ''' - reg_id = self._regfile.reg_id(name) - return self._regfile.write(reg_id, value) + return self._regfile.write(register, value) - def read_register(self, name): + def read_register(self, register): ''' A convenient method to read a register by name (this accepts alias) - @param name a register name as listed in all_registers + @param register a register name as listed in all_registers @param value a value @return It will return the written value possibly croped ''' - reg_id = self._regfile.reg_id(name) - return self._regfile.read(reg_id) + return self._regfile.read(register) # Pythonic acces to registers and aliases def __getattr__(self, name): ''' A pythonic version of read_register ''' assert name != '_regfile' - if hasattr(self, '_regfile') and name in self.all_registers: + if hasattr(self, '_regfile') and name in self._regfile: return self.read_register(name) - raise AttributeError(name) def __setattr__(self, name, value): ''' A pythonic version of write_register ''' - if hasattr(self, '_regfile') and name in self.all_registers: + if hasattr(self, '_regfile') and name in self._regfile: return self.write_register(name, value) object.__setattr__(self, name, value) - def getCanonicalRegisters(self): - values = [self.read_register(rname) for rname in self.canonical_registers] - d = dict(zip(self.canonical_registers, values)) - return d ############################# # Memory access @@ -372,9 +359,7 @@ class Cpu(object): if logger.level == logging.DEBUG : for l in str(self).split('\n'): logger.debug(l) - implementation(*instruction.operands) - self._icount+=1 @abstractmethod @@ -533,7 +518,7 @@ class InvalidPCException(Exception): super(InvalidPCException, self).__init__("Trying to execute invalid memory @%08x"%pc) self.pc=pc -class InstructionNotImplemented(Exception): +class InstructionNotImplementedError(Exception): ''' Exception raised when you try to execute an instruction that is not yet implemented in the emulator. Go to cpu.py and add it! diff --git a/manticore/core/cpu/arm.py b/manticore/core/cpu/arm.py index 2a9dde9..9e78b01 100644 --- a/manticore/core/cpu/arm.py +++ b/manticore/core/cpu/arm.py @@ -12,25 +12,6 @@ from bitwise import * from capstone import * from capstone.arm import * -from capstone.x86 import * - - -# no emulator by default -try: - from unicorn import * - from unicorn.x86_const import * - from unicorn.arm_const import * -except: - pass -MU = None - - - -# Custom Constants (avoid conflicts with capstone's arm constants) -ARM_REG_APSR_N = 1000 -ARM_REG_APSR_Z = 1001 -ARM_REG_APSR_C = 1002 -ARM_REG_APSR_V = 1003 import logging logger = logging.getLogger("CPU") @@ -70,28 +51,31 @@ class Armv7Operand(Operand): def __init__(self, cpu, op, **kwargs): super(Armv7Operand, self).__init__(cpu, op, **kwargs) + @property def size(self): assert self.op.type == ARM_OP_REG if self.op.reg >= ARM_REG_D0 and self.op.reg <= ARM_REG_D31: - return 8 + return 64 else: - return 4 + #FIXME check other types of operand sizes + return 32 def read(self, nbits=None, withCarry=False): - carry = self.cpu.regfile.read(ARM_REG_APSR_C) + carry = self.cpu.regfile.read('APSR_C') if self.op.type == ARM_OP_REG: - reg = self.cpu.regfile.read(self.op.reg) + register = self._reg_name(self.op.reg) + value = self.cpu.regfile.read(register) # XXX This can be an offset of 8, depending on ARM mode - if self.op.reg == ARM_REG_R15: - reg += 4 + if register in ('PC', 'R15'): + value += 4 if self.is_shifted(): shift = self.op.shift - reg, carry = self.cpu._Shift(reg, shift.type, shift.value, carry) + value, carry = self.cpu._Shift(value, shift.type, shift.value, carry) if self.op.subtracted: - reg = -reg + value = -value if withCarry: - return reg, carry - return reg + return value, carry + return value elif self.op.type == ARM_OP_IMM: imm = self.op.imm if self.op.subtracted: @@ -110,7 +94,8 @@ class Armv7Operand(Operand): def write(self, value, nbits=None): if self.op.type == ARM_OP_REG: - self.cpu.regfile.write(self.op.reg, value) + register = self._reg_name(self.op.reg) + self.cpu.regfile.write(register, value) elif self.op.type == ARM_OP_MEM: raise NotImplementedError('need to impl arm store mem') else: @@ -120,7 +105,8 @@ class Armv7Operand(Operand): if self.op.type == ARM_OP_REG: self.write(value) elif self.op.type == ARM_OP_MEM: - self.cpu.regfile.write(self.op.mem.base, value) + register = self._reg_name(self.op.mem.base) + self.cpu.regfile.write(register, value) else: raise NotImplementedError("writeback Operand unknown type", self.op.type) @@ -136,29 +122,27 @@ class Armv7Operand(Operand): def get_mem_offset(self): assert self.op.type == ARM_OP_MEM - mem = self.op.mem off = 0 - if mem.index: - idx = mem.scale * self.cpu.regfile.read(mem.index) - carry = self.cpu.regfile.read(ARM_REG_APSR_C) + 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 = mem.disp + off = self.mem.disp return -off if self.op.subtracted else off def get_mem_base_addr(self): assert self.op.type == ARM_OP_MEM - mem = self.op.mem - base = self.cpu.regfile.read(mem.base) + 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 mem.base == ARM_REG_PC else base + 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 @@ -172,90 +156,47 @@ class Armv7Operand(Operand): class Armv7RegisterFile(RegisterFile): - REGMAP = { - ARM_REG_R0: 0, - ARM_REG_R1: 1, - ARM_REG_R2: 2, - ARM_REG_R3: 3, - ARM_REG_R4: 4, - ARM_REG_R5: 5, - ARM_REG_R6: 6, - ARM_REG_R7: 7, - ARM_REG_R8: 8, - ARM_REG_R9: 9, - ARM_REG_R10: 10, - ARM_REG_R11: 11, - ARM_REG_R12: 12, - ARM_REG_R13: 13, # alias: ARM_REG_SP - ARM_REG_R14: 14, # alias: ARM_REG_LR - ARM_REG_R15: 15, # alias: ARM_REG_PC - - ARM_REG_D0: 16, - ARM_REG_D1: 17, - ARM_REG_D2: 18, - ARM_REG_D3: 19, - ARM_REG_D4: 20, - ARM_REG_D5: 21, - ARM_REG_D6: 22, - ARM_REG_D7: 23, - ARM_REG_D8: 24, - ARM_REG_D9: 25, - ARM_REG_D10: 26, - ARM_REG_D11: 27, - ARM_REG_D12: 28, - ARM_REG_D13: 29, - ARM_REG_D14: 30, - ARM_REG_D15: 31, - ARM_REG_D16: 32, - ARM_REG_D17: 33, - ARM_REG_D18: 34, - ARM_REG_D19: 35, - ARM_REG_D20: 36, - ARM_REG_D21: 37, - ARM_REG_D22: 38, - ARM_REG_D23: 39, - ARM_REG_D24: 40, - ARM_REG_D25: 41, - ARM_REG_D26: 42, - ARM_REG_D27: 43, - ARM_REG_D28: 44, - ARM_REG_D29: 45, - ARM_REG_D30: 46, - ARM_REG_D31: 47, - - ARM_REG_APSR_N: 48, - ARM_REG_APSR_Z: 49, - ARM_REG_APSR_C: 50, - ARM_REG_APSR_V: 51, - - } - def __init__(self): '''ARM Register file abstraction. GPRs use ints for read/write. APSR flags allow writes of bool/{1, 0} but always read bools. ''' - super(Armv7RegisterFile, self).__init__( ) - self.aliases = { 'STACK': 'SP', - 'PC': 'PC', # these three lines are technically unnecessary, but explicit is - 'SP': 'SP', # better than implicit - 'LR': 'LR', }#) - gpr = [Register(32) for x in xrange(16)] - vec = [Register(64) for x in xrange(32)] - bit_flags = [Register(1) for x in xrange(4)] - self.regs = gpr + vec + bit_flags + super(Armv7RegisterFile, self).__init__({ 'SB':'R9', + 'SL':'R10', + 'FP':'R11', + 'IP': 'R12', + 'STACK': 'R13', + 'SP': 'R13', + 'LR': 'R14', + 'PC': 'R15', } ) + self._regs = { } + #32 bit registers + for reg_name in ( 'R0', 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', + 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15' ): + self._regs[reg_name] = Register(32) + #64 bit registers + for reg_name in ( 'D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', + 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', + 'D17', 'D18', 'D19', 'D20', 'D21', 'D22', 'D23', 'D24', + 'D25', 'D26', 'D27', 'D28', 'D29', 'D30', 'D31'): + self._regs[reg_name] = Register(64) + #Flags + self._regs['APSR_N'] = Register(1) + self._regs['APSR_Z'] = Register(1) + self._regs['APSR_C'] = Register(1) + self._regs['APSR_V'] = Register(1) def _read_APSR(self): - N = self.read(ARM_REG_APSR_N) - Z = self.read(ARM_REG_APSR_Z) - C = self.read(ARM_REG_APSR_C) - V = self.read(ARM_REG_APSR_V) - apsr = 0 - def make_apsr_flag(flag_expr, offset): 'Helper for constructing an expression for the APSR register' return Operators.ITEBV(32, flag_expr, BitVecConstant(32, 1 << offset), BitVecConstant(32, 0)) + apsr = 0 + N = self.read('APSR_N') + Z = self.read('APSR_Z') + C = self.read('APSR_C') + V = self.read('APSR_V') + if any(issymbolic(x) for x in [N, Z, C, V]): apsr = (make_apsr_flag(N, 31) | make_apsr_flag(Z, 30) | @@ -268,50 +209,44 @@ class Armv7RegisterFile(RegisterFile): if V: apsr |= 1 << 28 return apsr + def _write_APSR(self, apsr): + ''' Auxiliar function - Writes flags from a full APSR (only 4 msb used) ''' V = Operators.EXTRACT(apsr, 28, 1) C = Operators.EXTRACT(apsr, 29, 1) Z = Operators.EXTRACT(apsr, 30, 1) N = Operators.EXTRACT(apsr, 31, 1) - self.write(ARM_REG_APSR_V, V) - self.write(ARM_REG_APSR_C, C) - self.write(ARM_REG_APSR_Z, Z) - self.write(ARM_REG_APSR_N, N) + self.write('APSR_V', V) + self.write('APSR_C', C) + self.write('APSR_Z', Z) + self.write('APSR_N', N) - - def read(self, reg_id): - if reg_id == ARM_REG_APSR: + def read(self, register): + assert register in self + if register == 'APSR': return self._read_APSR() - return self.regs[self.REGMAP[reg_id]].read() + register = self._alias(register) + return self._regs[register].read() - def write(self, reg_id, val): - if reg_id == ARM_REG_APSR: - return self._write_APSR(val) - reg_offset = self.REGMAP[reg_id] - reg = self.regs[reg_offset] - reg.write(val) + def write(self, register, value): + assert register in self + if register == 'APSR': + return self._write_APSR(value) + register = self._alias(register) + self._regs[register].write(value) @property def all_registers(self): - return ('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12','R13','R14','R15','D0','D1','D2', + return super(Armv7RegisterFile, self).all_registers + \ + ('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12','R13','R14','R15','D0','D1','D2', 'D3','D4','D5','D6','D7','D8','D9','D10','D11','D12','D13','D14','D15','D16','D17','D18','D19','D20', - 'D21','D22','D23','D24','D25','D26','D27','D28','D29','D30','D31','APSR_N','APSR_Z','APSR_C','APSR_V') + ('STACK','PC','SP','LR') + 'D21','D22','D23','D24','D25','D26','D27','D28','D29','D30','D31','APSR','APSR_N','APSR_Z','APSR_C','APSR_V') @property def canonical_registers(self): - return ('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12', 'SP', 'LR', 'PC', 'APSR') + return ('R0','R1','R2','R3','R4','R5','R6','R7','R8','R9','R10','R11','R12','R13','R14','R15','APSR') - def reg_name(self, reg_id): - reg_offset = self.REGMAP[reg_id] - return self.all_registers[reg_offset] - - def reg_id(self, reg_name): - reg_name = self.aliases.get(reg_name, reg_name) - return globals()['ARM_REG_'+reg_name] - - def __contains__(self, reg_id): - return reg_id in self.all_registers class Armv7Cpu(Cpu): '''Note: In this implementation, PC contains address of current @@ -361,22 +296,6 @@ class Armv7Cpu(Cpu): logger.info("Emulator wants this regs %r", reg_values) return reg_values - def stack_get(self): - return self.STACK - - def stack_set(self, value): - self.STACK = value - - - def pc_get(self): - return self.PC - def pc_set(self, value): - self.PC=value - - def stack_sub(self, value): - self.STACK -= value - def stack_add(self, value): - self.STACK += value # Flags that are the result of arithmetic instructions. Unconditionally # set, but conditionally committed. @@ -395,7 +314,7 @@ class Armv7Cpu(Cpu): ''' unupdated_flags = self._last_flags.viewkeys() - flags.viewkeys() for flag in unupdated_flags: - flag_name = globals()['ARM_REG_APSR_%s'%(flag,)] + flag_name = 'APSR_{}'.format(flag) self._last_flags[flag] = self.regfile.read(flag_name) self._last_flags.update(flags) @@ -404,7 +323,7 @@ class Armv7Cpu(Cpu): if self.instruction.mnemonic == 'adc': return for flag, val in self._last_flags.iteritems(): - flag_name = globals()['ARM_REG_APSR_%s'%(flag,)] + flag_name = 'APSR_{}'.format(flag) self.regfile.write(flag_name, val) @@ -416,7 +335,8 @@ class Armv7Cpu(Cpu): if _type in (ARM_SFT_RRX, ARM_SFT_RRX_REG) and amount != 1: amount = 1 - if _type in range(ARM_SFT_ASR_REG, ARM_SFT_RRX_REG + 1): + elif _type in range(ARM_SFT_ASR_REG, ARM_SFT_RRX_REG + 1): + amount = cpu.instruction.reg_name(amount).upper() amount = Operators.EXTRACT(cpu.regfile.read(amount), 0, 8) if amount == 0: @@ -441,29 +361,29 @@ class Armv7Cpu(Cpu): # TODO add to abstract cpu, and potentially remove stacksub/add from it? def stack_push(self, data): if isinstance(data, (int, long)): - self.stack_sub(self.address_bit_size/8) - self.write_int(self.stack_get(), data, self.address_bit_size) + self.SP -= self.address_bit_size/8 + self.write_int(self.SP, data, self.address_bit_size) elif isinstance(data, BitVec): - self.stack_sub(data.size/8) - self.write_int(self.stack_get(), data, data.size) + self.SP -= data.size/8 + self.write_int(self.SP, data, data.size) elif isinstance(data, str): - self.stack_sub(len(data)) - self.write(self.stack_get(), data) + self.SP -= len(data) + self.write(self.SP, data) else: raise NotImplementedError('unsupported type for stack push data') - return self.stack_get() + return self.SP def stack_peek(self, nbytes=4): - return self.read(self.stack_get(), nbytes) + return self.read(self.SP, nbytes) def stack_pop(self, nbytes=4): # TODO is the distinction between load and read really in the op size? nbits = nbytes * 8 if nbits == self.address_bit_size: - val = self.read_int(self.stack_get(), nbits) + val = self.read_int(self.SP, nbits) else: - val = self.read(self.stack_get(), nbytes) - self.stack_add(nbytes) + val = self.read(self.SP, nbytes) + self.SP += nbytes return val def read(self, addr, nbytes): @@ -485,28 +405,6 @@ class Armv7Cpu(Cpu): return 'ASR' return OP_NAME_MAP.get(name, name) - def readOperand(self, op): - if op.type == ARM_OP_REG: - return self.regfile.read(op.reg) - elif op.type == ARM_OP_IMM: - return op.imm - elif op.type == ARM_OP_MEM: - raise NotImplementedError('need to impl arm load mem') - else: - raise NotImplementedError("readOperand unknown type", op.type) - - def writeOperand(self, op, value): - if op.type == ARM_OP_REG: - self.regfile.write(op.reg, value) - elif op.type == ARM_OP_MEM: - raise NotImplementedError('need to impl arm store mem') - else: - raise NotImplementedError("writeOperand unknown type", op.type) - - def getOperandAddress(self, op): - # TODO IMPLEMENT - return -1 - def _wrap_operands(self, ops): return [Armv7Operand(self, op) for op in ops] @@ -524,10 +422,10 @@ class Armv7Cpu(Cpu): cpu._force_next = False return True - C = cpu.regfile.read(ARM_REG_APSR_C) - N = cpu.regfile.read(ARM_REG_APSR_N) - V = cpu.regfile.read(ARM_REG_APSR_V) - Z = cpu.regfile.read(ARM_REG_APSR_Z) + C = cpu.regfile.read('APSR_C') + N = cpu.regfile.read('APSR_N') + V = cpu.regfile.read('APSR_V') + Z = cpu.regfile.read('APSR_Z') if cc == ARM_CC_AL: ret = True elif cc == ARM_CC_EQ: ret = Z @@ -553,58 +451,23 @@ class Armv7Cpu(Cpu): return ret - def getCanonicalRegisters(cpu): - #TODO: Clean up the way this interacts with the regfile - names = ['r%d'%(i,) for i in range(13)] + ['sp', 'lr', 'pc'] - values = [cpu.regfile.regs[i].read() for i in range(16)] - d = dict(zip(names, values)) - - N = cpu.regfile.read(ARM_REG_APSR_N) - Z = cpu.regfile.read(ARM_REG_APSR_Z) - C = cpu.regfile.read(ARM_REG_APSR_C) - V = cpu.regfile.read(ARM_REG_APSR_V) - - cpsr = 0 - - def make_cpsr_flag(flag_expr, offset): - 'Helper for constructing an expression for the CPSR register' - return Operators.ITEBV(cpu.address_bit_size, flag_expr, - BitVecConstant(cpu.address_bit_size, 1 << offset), - BitVecConstant(cpu.address_bit_size, 0)) - if any(issymbolic(x) for x in [N, Z, C, V]): - cpsr = (make_cpsr_flag(N, 31) | - make_cpsr_flag(Z, 30) | - make_cpsr_flag(C, 29) | - make_cpsr_flag(V, 28)) - else: - if N: cpsr |= 1 << 31 - if Z: cpsr |= 1 << 30 - if C: cpsr |= 1 << 29 - if V: cpsr |= 1 << 28 - - d['cpsr'] = cpsr - - return d - - def getSyscallRetReg(self): - return 'r0' def get_syscall_description(cpu): # EABI standards: # syscall # is in R7 # arguments are passed in R0-R6 # retval is passed in R0 - index = cpu.regfile.read(ARM_REG_R7) + index = cpu.regfile.read('R7') - arg_indeces = [globals()['ARM_REG_R%d' % i] for i in range(0, 7)] + arg_indeces = ['R{}'.format(i) for i in range(0, 7)] arguments = [cpu.regfile.read(idx) for idx in arg_indeces] def writeResult(result, cpu = cpu): - cpu.regfile.write(ARM_REG_R0, result) + cpu.regfile.write('R0', result) return (index, arguments, writeResult) def getSyscallResult(self): - return self.regfile.read(ARM_REG_R0) + return self.regfile.read('R0') @instruction def MOV(cpu, dest, src): @@ -707,7 +570,7 @@ class Armv7Cpu(Cpu): @instruction def ADC(cpu, dest, op1, op2): - carry = cpu.regfile.read(ARM_REG_APSR_C) + carry = cpu.regfile.read('APSR_C') result, carry, overflow = cpu._ADD(op1.read(), op2.read(), carry) dest.write(result) return result, carry, overflow @@ -732,7 +595,7 @@ class Armv7Cpu(Cpu): @instruction def SBC(cpu, dest, src, add): - carry = cpu.regfile.read(ARM_REG_APSR_C) + carry = cpu.regfile.read('APSR_C') result, carry, overflow = cpu._ADD(src.read(), ~add.read(), carry) dest.write(result) return result, carry, overflow @@ -749,13 +612,13 @@ class Armv7Cpu(Cpu): @instruction def BLE(cpu, dest): cpu.PC = Operators.ITEBV(cpu.address_bit_size, - cpu.regfile.read(ARM_REG_APSR_Z), dest.read(), cpu.PC) + cpu.regfile.read('APSR_Z'), dest.read(), cpu.PC) @instruction def BL(cpu, label): - next_instr_addr = cpu.regfile.read(ARM_REG_PC) - cpu.regfile.write(ARM_REG_LR, next_instr_addr) - cpu.regfile.write(ARM_REG_PC, label.read()) + next_instr_addr = cpu.regfile.read('PC') + cpu.regfile.write('LR', next_instr_addr) + cpu.regfile.write('PC', label.read()) @instruction @@ -765,9 +628,9 @@ class Armv7Cpu(Cpu): ## THUMB and regular modes, so we use the addresses as is. TODO: Handle ## thumb correctly and fix this target = dest.read() - next_instr_addr = cpu.regfile.read(ARM_REG_PC) #- 2 - cpu.regfile.write(ARM_REG_LR, next_instr_addr) # | 1) - cpu.regfile.write(ARM_REG_PC, target & ~1) + next_instr_addr = cpu.regfile.read('PC') #- 2 + cpu.regfile.write('LR', next_instr_addr) # | 1) + cpu.regfile.write('PC', target & ~1) @instruction def CMP(cpu, reg, cmp): @@ -776,28 +639,14 @@ class Armv7Cpu(Cpu): @instruction def POP(cpu, *regs): - sp = cpu.stack_get() - invalid = 0 - - # "The SP can only be in the list before ARMv7. ARM deprecates any use - # of ARM instructions that include the SP, and the value of the SP after - # such an instruction is UNKNOWN" (pg A8-537) - valid = lambda r: r.op.type == ARM_OP_REG and r.op.reg != ARM_REG_SP - for reg in regs: - assert valid(reg) val = cpu.stack_pop(cpu.address_bit_size / 8) reg.write(val) @instruction def PUSH(cpu, *regs): - # ARM deprecates the use of ARM instructions that include the PC in the - # list (pg A8-539) - valid = lambda r: r.op.type == ARM_OP_REG and r.op.reg != ARM_REG_PC - high_to_low_regs = regs[::-1] for reg in high_to_low_regs: - assert valid(reg) cpu.stack_push(reg.read()) @@ -927,10 +776,9 @@ class Armv7Cpu(Cpu): elif insn_id == ARM_INS_LSR: srtype = ARM_SFT_LSR_REG - carry = cpu.regfile.read(ARM_REG_APSR_C) + carry = cpu.regfile.read('APSR_C') if rest: - amount_val = rest[0].op.reg - result, carry = cpu._Shift(op.read(), srtype, amount_val, carry) + result, carry = cpu._Shift(op.read(), srtype, rest[0].op.reg, carry) else: result, carry = op.read(withCarry=True) dest.write(result) @@ -988,9 +836,8 @@ class Armv7Cpu(Cpu): def _VSTM(cpu, address, *regs): for reg in regs: - size = reg.size() - cpu.write_int(address, reg.read(), size * 8) - address += size + cpu.write_int(address, reg.read(), reg.size) + address += reg.size/8 return address @@ -1010,3 +857,4 @@ class Armv7Cpu(Cpu): @instruction def STCL(cpu, *operands): pass + diff --git a/manticore/core/cpu/x86.py b/manticore/core/cpu/x86.py index 6f5dd15..7972aec 100644 --- a/manticore/core/cpu/x86.py +++ b/manticore/core/cpu/x86.py @@ -443,16 +443,11 @@ class AMD64RegFile(RegisterFile): for reg in ('FPSW', 'FPTAG', 'FPCW'): self._registers[reg] = 0 + self._cache = {} for name in ('AF', 'CF', 'DF', 'IF', 'OF', 'PF', 'SF', 'ZF'): self.write(name, False) - def reg_name(self, reg_id): - return reg_id - - def reg_id(self, reg_name): - return self._aliases.get(reg_name, reg_name) - @property def all_registers(self): return tuple( self._table.keys() + @@ -462,8 +457,8 @@ class AMD64RegFile(RegisterFile): def canonical_registers(self): return self._canonical_registers - def __contains__(self, reg_id): - return reg_id in self.all_registers + def __contains__(self, register): + return register in self.all_registers def _set_bv(self, register_id, register_size, offset, size, reset, value): if isinstance(value, (int,long)): @@ -550,9 +545,8 @@ class AMD64RegFile(RegisterFile): for flag, offset in self._flags.iteritems(): self.write(flag, Operators.EXTRACT(res, offset, 1)) - def write(self, reg_id, value): - name = self.reg_name(reg_id) - + def write(self, name, value): + name = self._alias(name) if name in ('ST0', 'ST1', 'ST2', 'ST3', 'ST4', 'ST5', 'ST6', 'ST7'): name = 'FP%d' % ((self.read('TOP') + int(name[2]) ) & 7) @@ -574,15 +568,14 @@ class AMD64RegFile(RegisterFile): self._update_cache(name, value) return value - def _update_cache(self,name, value): + def _update_cache(self, name, value): self._cache[name] = value for affected in self._affects[name]: assert affected != name self._cache.pop(affected, None) - def read(self, reg_id): - name = self.reg_name(reg_id) - + def read(self, name): + name = self._alias(name) if name in ('ST0', 'ST1', 'ST2', 'ST3', 'ST4', 'ST5', 'ST6', 'ST7'): name = 'FP%d' % ((self.read('TOP') + int(name[2]) ) & 7) if name in self._cache: @@ -605,24 +598,16 @@ class AMD64RegFile(RegisterFile): ########################### # Operand Wrapper class AMD64Operand(Operand): - def _reg_name(self, reg_id): - if reg_id <= 0 : - return '(invalid)' - return self.cpu.instruction.reg_name(reg_id).upper() - + ''' This class deals with capstone X86 operands ''' def __init__(self, cpu, op, **kwargs): super(AMD64Operand, self).__init__(cpu, op, **kwargs) - self.cpu=cpu - self.op=op - if op.type == X86_OP_MEM: - self.mem = AMD64Operand.MemSpec(self) #################################3 # Operand access def address(self): cpu, o = self.cpu, self.op address = 0 - if o.mem.segment != 0: + if self.mem.segment is not None: seg = self.mem.segment base, size, ty = cpu.get_descriptor(cpu.read_register(seg)) address += base #todo check limits and perms @@ -630,18 +615,18 @@ class AMD64Operand(Operand): #FIXME inspect operand or cpu.instruction and decide # the correct default segment for instruction seg = 'DS' - if o.mem.base != 0 and self.mem.base in ['SP', 'ESP', 'EBP']: + if self.mem.base is not None and self.mem.base in ['SP', 'ESP', 'EBP']: seg = 'SS' base, size, ty = cpu.get_descriptor(cpu.read_register(seg)) address += base #todo check limits and perms - if o.mem.base != 0: + if self.mem.base is not None: base = self.mem.base address += cpu.read_register(base) - if o.mem.index != 0: + if self.mem.index is not None: index = self.mem.index - address += o.mem.scale*cpu.read_register(index) - if o.mem.disp != 0: - address += o.mem.disp + address += self.mem.scale*cpu.read_register(index) + + address += self.mem.disp return address & ((1<> 3)) + self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x80000000) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x80000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0xf0000000) + self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr2(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x40000000) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x40000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (0x40000000 >> 3)) + self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror_norm(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x8) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x8) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0x1) + self.assertEqual(self.rf.read('R3'), 0x1) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x3) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x3) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0x60000000) + self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("adc r3, r1, r2") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_basic(self): self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 4) + self.assertEqual(self.rf.read('R3'), 4) @itest_custom("adc r3, r1, r2, ror #3") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_reg_sft_ror(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x3) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x3) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0x60000001) + self.assertEqual(self.rf.read('R3'), 0x60000001) # TODO what is shifter_carry_out in the manual, A8-291? it gets set to # Bit[0] presumably, but i have no clue what it is. Not mentioned again in # manual. @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx(self): - self.rf.write(ARM_REG_APSR_C, 0x0) - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('APSR_C', 0x0) + self.rf.write('R1', 0x0) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 31 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2(self): - self.rf.write(ARM_REG_APSR_C, 0x1) - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('APSR_C', 0x1) + self.rf.write('R1', 0x0) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 32 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) @itest_custom("add r3, r1, r2, lsl r4") def test_add_reg_sft_lsl_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x1) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (1 << 3)) + self.assertEqual(self.rf.read('R3'), (1 << 3)) @itest_custom("add r3, r1, r2, lsr r4") def test_add_reg_sft_lsr_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x8) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x8) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (0x8 >> 3)) + self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x80000000) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x80000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0xf0000000) + self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr2_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x40000000) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x40000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (0x40000000 >> 3)) + self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_norm_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x8) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x8) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 1) + self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R4, 0x3) - self.rf.write(ARM_REG_R2, 0x3) + self.rf.write('R1', 0x0) + self.rf.write('R4', 0x3) + self.rf.write('R2', 0x3) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0x60000000) + self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_APSR_C, 0x0) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('R1', 0x0) + self.rf.write('APSR_C', 0x0) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 31 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2_reg(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_APSR_C, 0x1) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('R1', 0x0) + self.rf.write('APSR_C', 0x1) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 32 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) # ADDS @itest_custom("adds r3, r1, 55") def test_adds_imm_norm(self): - self.rf.write(ARM_REG_R1, 44) + self.rf.write('R1', 44) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 99) + self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0x100") def test_adds_imm_mod_imm_min(self): - self.rf.write(ARM_REG_R1, 44) + self.rf.write('R1', 44) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 44 + 0x100) + self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0xff000000") def test_adds_imm_mod_imm_max(self): - self.rf.write(ARM_REG_R1, 44) + self.rf.write('R1', 44) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 44 + 0xff000000) + self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, 0x1000000") def test_adds_imm_carry(self): - self.rf.write(ARM_REG_R1, 0xff000001) + self.rf.write('R1', 0xff000001) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 1) + self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, 0x80000000") def test_adds_imm_carry_overflow(self): - self.rf.write(ARM_REG_R1, 0x80000001) + self.rf.write('R1', 0x80000001) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 1) + self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, 0x1") def test_adds_imm_overflow(self): - self.rf.write(ARM_REG_R1, (2 ** 31 - 1)) + self.rf.write('R1', (2 ** 31 - 1)) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0x80000000) + self.assertEqual(self.rf.read('R3'), 0x80000000) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r3, 0x0") def test_adds_imm_zf(self): - self.rf.write(ARM_REG_R3, 0) + self.rf.write('R3', 0) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0) + self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_norm(self): - self.rf.write(ARM_REG_R1, 44) - self.rf.write(ARM_REG_R2, 55) + self.rf.write('R1', 44) + self.rf.write('R2', 55) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 99) + self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_min(self): - self.rf.write(ARM_REG_R1, 44) - self.rf.write(ARM_REG_R2, 0x100) + self.rf.write('R1', 44) + self.rf.write('R2', 0x100) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 44 + 0x100) + self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_max(self): - self.rf.write(ARM_REG_R1, 44) - self.rf.write(ARM_REG_R2, 0xff000000) + self.rf.write('R1', 44) + self.rf.write('R2', 0xff000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 44 + 0xff000000) + self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry(self): - self.rf.write(ARM_REG_R1, 0x1000000) - self.rf.write(ARM_REG_R2, 0xff000001) + self.rf.write('R1', 0x1000000) + self.rf.write('R2', 0xff000001) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 1) + self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_overflow(self): - self.rf.write(ARM_REG_R1, (2 ** 31 - 1)) - self.rf.write(ARM_REG_R2, 1) + self.rf.write('R1', (2 ** 31 - 1)) + self.rf.write('R2', 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (1 << 31)) + self.assertEqual(self.rf.read('R3'), (1 << 31)) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry_overflow(self): - self.rf.write(ARM_REG_R1, 0x80000001) - self.rf.write(ARM_REG_R2, 0x80000000) + self.rf.write('R1', 0x80000001) + self.rf.write('R2', 0x80000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 1) + self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_zf(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x0) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x0) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0) + self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x80000000) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x80000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 0xf0000000) + self.assertEqual(self.rf.read('R3'), 0xf0000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr2(self): - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 0x40000000) + self.rf.write('R1', 0x0) + self.rf.write('R2', 0x40000000) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), (0x40000000 >> 3)) + self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx(self): - self.rf.write(ARM_REG_APSR_C, 0x0) - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('APSR_C', 0x0) + self.rf.write('R1', 0x0) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 31 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx2(self): - self.rf.write(ARM_REG_APSR_C, 0x1) - self.rf.write(ARM_REG_R1, 0x0) - self.rf.write(ARM_REG_R2, 2 ** 32 - 1) + self.rf.write('APSR_C', 0x1) + self.rf.write('R1', 0x0) + self.rf.write('R2', 2 ** 32 - 1) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R3), 2 ** 32 - 1) + self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) self._checkFlagsNZCV(1, 0, 0, 0) # LDR imm @@ -634,14 +629,14 @@ class Armv7CpuInstructions(unittest.TestCase): def test_ldr_imm_off_none(self): self.cpu.stack_push(42) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) + self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #4]") def test_ldr_imm_off_pos(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) + self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #-4]") def test_ldr_imm_off_neg(self): @@ -649,7 +644,7 @@ class Armv7CpuInstructions(unittest.TestCase): self.cpu.stack_push(41) self.cpu.STACK += 4 self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 41) + self.assertEqual(self.rf.read('R1'), 41) @itest_custom("ldr r1, [sp, #4]!") def test_ldr_imm_preind_pos(self): @@ -657,8 +652,8 @@ class Armv7CpuInstructions(unittest.TestCase): self.cpu.stack_push(41) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack + 4) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, #-4]!") def test_ldr_imm_preind_neg(self): @@ -667,108 +662,108 @@ class Armv7CpuInstructions(unittest.TestCase): self.cpu.STACK += 4 pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 41) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack - 4) + self.assertEqual(self.rf.read('R1'), 41) + self.assertEqual(self.rf.read('SP'), pre_stack - 4) @itest_custom("ldr r1, [sp], #5") def test_ldr_imm_postind_pos(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack + 5) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack + 5) @itest_custom("ldr r1, [sp], #-5") def test_ldr_imm_postind_neg(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack - 5) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack - 5) # LDR reg @itest_custom("ldr r1, [sp, r2]") def test_ldr_reg_off(self): - self.cpu.regfile.write(ARM_REG_R2, 4) + self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) + self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2]") def test_ldr_reg_off_neg(self): - self.cpu.regfile.write(ARM_REG_R2, 4) + self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 4 self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 48) + self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2, lsl #3]") def test_ldr_reg_off_shift(self): - self.cpu.regfile.write(ARM_REG_R2, 1) + self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.stack_push(40) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) + self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2, lsl #3]") def test_ldr_reg_off_neg_shift(self): - self.cpu.regfile.write(ARM_REG_R2, 1) + self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 48) + self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2]!") def test_ldr_reg_preind(self): - self.cpu.regfile.write(ARM_REG_R2, 4) + self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack + 4) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, -r2, lsl #3]!") def test_ldr_reg_preind_shift(self): - self.cpu.regfile.write(ARM_REG_R2, 1) + self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 48) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack - 8) + self.assertEqual(self.rf.read('R1'), 48) + self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("ldr r1, [sp], r2") def test_ldr_reg_postind(self): - self.cpu.regfile.write(ARM_REG_R2, 4) + self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack + 4) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp], -r2, lsl #3") def test_ldr_reg_postind_neg_shift(self): - self.cpu.regfile.write(ARM_REG_R2, 1) + self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 42) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack - 8) + self.assertEqual(self.rf.read('R1'), 42) + self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("pop {r1}") def test_pop_one_reg(self): self.cpu.stack_push(0x55) pre_stack = self.cpu.STACK self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 0x55) - self.assertEqual(self.rf.read(ARM_REG_SP), pre_stack + 4) + self.assertEqual(self.rf.read('R1'), 0x55) + self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("pop {r1, r2, r3}") def test_pop_multops(self): @@ -776,9 +771,9 @@ class Armv7CpuInstructions(unittest.TestCase): for v in vals: self.cpu.stack_push(v) self.cpu.execute() - self.assertEqual(self.rf.read(ARM_REG_R1), 0xAA) - self.assertEqual(self.rf.read(ARM_REG_R2), 0x55) - self.assertEqual(self.rf.read(ARM_REG_R3), 0x01) + self.assertEqual(self.rf.read('R1'), 0xAA) + self.assertEqual(self.rf.read('R2'), 0x55) + self.assertEqual(self.rf.read('R3'), 0x01) @itest_custom("push {r1}") @itest_setregs("R1=3") @@ -792,7 +787,7 @@ class Armv7CpuInstructions(unittest.TestCase): pre_sp = self.cpu.STACK self.cpu.execute() sp = self.cpu.STACK - self.assertEqual(self.rf.read(ARM_REG_SP), pre_sp - (3 * 4)) + self.assertEqual(self.rf.read('SP'), pre_sp - (3 * 4)) self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('> 3) + self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R0=0x1000") @itest("lsr r0, r0, #3") def test_lsr_reg_imm(self): - self.assertEqual(self.rf.read(ARM_REG_R0), 0x1000 >> 3) + self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R2=29") @itest("RSB r2, r2, #31") def test_rsb_imm(self): # Diverging instruction from trace - self.assertEqual(self.rf.read(ARM_REG_R2), 2) + self.assertEqual(self.rf.read('R2'), 2) def test_flag_state_continuity(self): '''If an instruction only partially updates flags, cpu.setFlags should @@ -1266,11 +1261,11 @@ class Armv7CpuInstructions(unittest.TestCase): // ovf should still be 1 ''' - self.rf.write(ARM_REG_R1, (2 ** 31 - 1)) + self.rf.write('R1', (2 ** 31 - 1)) self._setupCpu("adds r2, r1, #0x1") self.cpu.execute() - self.rf.write(ARM_REG_R1, 1) - self.rf.write(ARM_REG_R3, 0) + self.rf.write('R1', 1) + self.rf.write('R3', 0) self.mem.write(self.cpu.PC, assemble("tst r3, r1")) self.cpu.execute() self._checkFlagsNZCV(0, 1, 0, 1) @@ -1278,86 +1273,72 @@ class Armv7CpuInstructions(unittest.TestCase): @itest_setregs("R1=30", "R2=10") @itest("MUL R1, R2") def test_mul_reg(self): - self.assertEqual(self.rf.read(ARM_REG_R1), 300) + self.assertEqual(self.rf.read('R1'), 300) @itest_setregs("R1=30", "R2=10") @itest("MUL R3, R1, R2") def test_mul_reg_w_dest(self): - self.assertEqual(self.rf.read(ARM_REG_R3), 300) + self.assertEqual(self.rf.read('R3'), 300) @itest_setregs("R2=10", "R3=15", "R4=7") @itest("MLA R1, R2, R3, R4") def test_mla_reg(self): - self.assertEqual(self.rf.read(ARM_REG_R1), 157) + self.assertEqual(self.rf.read('R1'), 157) @itest_setregs("R1=0xFF") @itest("BIC R2, R1, #0x10") def test_bic_reg_imm(self): - self.assertEqual(self.rf.read(ARM_REG_R2), 0xEF) + self.assertEqual(self.rf.read('R2'), 0xEF) @itest_setregs("R1=0x1008") @itest("BLX R1") def test_blx_reg(self): - self.assertEqual(self.rf.read(ARM_REG_PC), 0x1008) - self.assertEqual(self.rf.read(ARM_REG_LR), 0x1004) + self.assertEqual(self.rf.read('PC'), 0x1008) + self.assertEqual(self.rf.read('LR'), 0x1004) @itest_setregs("R1=0x1009") @itest("BLX R1") def test_blx_reg_thumb(self): - self.assertEqual(self.rf.read(ARM_REG_PC), 0x1008) - self.assertEqual(self.rf.read(ARM_REG_LR), 0x1004) + self.assertEqual(self.rf.read('PC'), 0x1008) + self.assertEqual(self.rf.read('LR'), 0x1004) @itest_setregs("R1=0xffffffff", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull(self): mul = 0xffffffff * 2 - pre_c = self.rf.read(ARM_REG_APSR_C) - pre_v = self.rf.read(ARM_REG_APSR_V) - self.assertEqual(self.rf.read(ARM_REG_R1), mul & Mask(32)) - self.assertEqual(self.rf.read(ARM_REG_R2), mul >> 32) + pre_c = self.rf.read('APSR_C') + pre_v = self.rf.read('APSR_V') + self.assertEqual(self.rf.read('R1'), mul & Mask(32)) + self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=2", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull_still32(self): mul = 2 * 2 - pre_c = self.rf.read(ARM_REG_APSR_C) - pre_v = self.rf.read(ARM_REG_APSR_V) - self.assertEqual(self.rf.read(ARM_REG_R1), mul & Mask(32)) - self.assertEqual(self.rf.read(ARM_REG_R2), mul >> 32) + pre_c = self.rf.read('APSR_C') + pre_v = self.rf.read('APSR_V') + self.assertEqual(self.rf.read('R1'), mul & Mask(32)) + self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=0xfffffffe", "R2=0xfffffffe") @itest("UMULLS R1, R2, R1, R2") def test_umull_max(self): mul = 0xfffffffe ** 2 - pre_c = self.rf.read(ARM_REG_APSR_C) - pre_v = self.rf.read(ARM_REG_APSR_V) - self.assertEqual(self.rf.read(ARM_REG_R1), mul & Mask(32)) - self.assertEqual(self.rf.read(ARM_REG_R2), mul >> 32) + pre_c = self.rf.read('APSR_C') + pre_v = self.rf.read('APSR_V') + self.assertEqual(self.rf.read('R1'), mul & Mask(32)) + self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(1, 0, pre_c, pre_v) @itest_setregs("R1=3", "R2=0") @itest("UMULLS R1, R2, R1, R2") def test_umull_z(self): mul = 3 * 0 - pre_c = self.rf.read(ARM_REG_APSR_C) - pre_v = self.rf.read(ARM_REG_APSR_V) - self.assertEqual(self.rf.read(ARM_REG_R1), mul & Mask(32)) - self.assertEqual(self.rf.read(ARM_REG_R2), (mul >> 32) & Mask(32)) + pre_c = self.rf.read('APSR_C') + pre_v = self.rf.read('APSR_V') + self.assertEqual(self.rf.read('R1'), mul & Mask(32)) + self.assertEqual(self.rf.read('R2'), (mul >> 32) & Mask(32)) self._checkFlagsNZCV(0, 1, pre_c, pre_v) - # Misc - - def test_getCanonicalRegisters(self): - for i, reg in enumerate(self.rf.canonical_registers): - if reg not in ('sp', 'pc'): - reg = reg.upper() - setattr(self.cpu, reg, i) - self._setupCpu("add r0, r0, 1") - - ideal = {'r4': 4, 'r5': 5, 'r6': 6, 'r7': 7, 'r0': 0, 'r1': 1, 'r2': 2, 'r3': 3, - 'r11': 11, 'r8': 8, 'r9': 9, 'pc': 4096, 'lr': 14, 'r12': 12, 'r10': 10, - 'cpsr': 0, 'sp': 65536} - - self.assertEqual(ideal, self.cpu.getCanonicalRegisters()) diff --git a/tests/test_armv7rf.py b/tests/test_armv7rf.py index f22719c..441d0c5 100644 --- a/tests/test_armv7rf.py +++ b/tests/test_armv7rf.py @@ -10,57 +10,66 @@ class Armv7RF(unittest.TestCase): self.r = RF() def test_init_state(self): - self.assertEqual(self.r.read(ARM_REG_R0), 0) + self.assertEqual(self.r.read('R0'), 0) def test_write_read(self): - self.r.write(ARM_REG_R0, 1) - self.assertEqual(self.r.read(ARM_REG_R0), 1) + self.r.write('R0', 1) + self.assertEqual(self.r.read('R0'), 1) def test_write_read_sp(self): - self.r.write(ARM_REG_SP, 1) - self.assertEqual(self.r.read(ARM_REG_SP), 1) + self.r.write('SP', 1) + self.assertEqual(self.r.read('SP'), 1) def test_flag_wr(self): - self.r.write(ARM_REG_APSR_Z, True) - self.assertEqual(self.r.read(ARM_REG_APSR_Z), True) + self.r.write('APSR_Z', True) + self.assertEqual(self.r.read('APSR_Z'), True) def test_flag_wr_f(self): - self.r.write(ARM_REG_APSR_Z, False) - self.assertEqual(self.r.read(ARM_REG_APSR_Z), False) - - def test_reg_name(self): - self.assertEqual(self.r.reg_name(ARM_REG_R0), 'R0') + self.r.write('APSR_Z', False) + self.assertEqual(self.r.read('APSR_Z'), False) def test_bad_reg_name(self): - with self.assertRaises(KeyError): - nonexistant_id = 9999 - self.r.reg_name(nonexistant_id) - - def test_reg_id(self): - self.assertEqual(self.r.reg_id('R0'), ARM_REG_R0) - - def test_bad_reg_id(self): - with self.assertRaises(KeyError): - self.r.reg_id('XXX') + with self.assertRaises(AssertionError): + nonexistant_reg = "Pc" + self.r.read(nonexistant_reg) def test_flag_wr(self): - self.r.write(ARM_REG_APSR, 0xffffffff) - self.assertEqual(self.r.read(ARM_REG_APSR), 0xf0000000) #4 more significant bits used - self.assertEqual(self.r.read(ARM_REG_APSR_V), True) - self.assertEqual(self.r.read(ARM_REG_APSR_C), True) - self.assertEqual(self.r.read(ARM_REG_APSR_Z), True) - self.assertEqual(self.r.read(ARM_REG_APSR_N), True) + self.r.write('APSR', 0xffffffff) + self.assertEqual(self.r.read('APSR'), 0xf0000000) #4 more significant bits used + self.assertEqual(self.r.read('APSR_V'), True) + self.assertEqual(self.r.read('APSR_C'), True) + self.assertEqual(self.r.read('APSR_Z'), True) + self.assertEqual(self.r.read('APSR_N'), True) - self.r.write(ARM_REG_APSR_N, False) - self.assertEqual(self.r.read(ARM_REG_APSR), 0x70000000) + self.r.write('APSR_N', False) + self.assertEqual(self.r.read('APSR'), 0x70000000) - self.r.write(ARM_REG_APSR_Z, False) - self.assertEqual(self.r.read(ARM_REG_APSR), 0x30000000) + self.r.write('APSR_Z', False) + self.assertEqual(self.r.read('APSR'), 0x30000000) - self.r.write(ARM_REG_APSR_C, False) - self.assertEqual(self.r.read(ARM_REG_APSR), 0x10000000) + self.r.write('APSR_C', False) + self.assertEqual(self.r.read('APSR'), 0x10000000) - self.r.write(ARM_REG_APSR_V, False) - self.assertEqual(self.r.read(ARM_REG_APSR), 0x00000000) + self.r.write('APSR_V', False) + self.assertEqual(self.r.read('APSR'), 0x00000000) + def test_register_independence_wr(self): + regs = ( 'R0', 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', + 'R9', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15' ) + aliases = {'SB':'R9', 'SL':'R10', 'FP':'R11', 'IP': 'R12', 'STACK': 'R13', 'SP': 'R13', 'LR': 'R14', 'PC': 'R15' } + + for j in xrange(16): + for i in xrange(16): + if i == j: + self.r.write(regs[i], 0x41424344) + else: + self.r.write(regs[i], 0) + for a,b in aliases.items(): + self.assertEqual(self.r.read(a), self.r.read(b)) + + for i in xrange(16): + if i == j: + self.assertEqual(self.r.read(regs[i]), 0x41424344 ) + else: + self.assertEqual(self.r.read(regs[i]), 0x00000000 )