manticore/tests/test_unicorn.py
feliam 520a9be47d Dev - events (#341)
* Wip refactoring

* Executor and exceptions refactor wip wip

* Fixing all_insts auto tests

* Visited and generate testcase now at manticore api level

* Aggregating state statistics into executor statistics

* Wip refactoring

* Executor and exceptions refactor wip wip

* Fixing all_insts auto tests

* Visited and generate testcase now at manticore api level

* Aggregating state statistics into executor statistics

* forwarding events wip

* state setstate fix and setup_stack merge fix

* will_terminate_state fix and tests skipped

* Update all ConcretizeRegister and ConcretizeMemory

* Wip refactoring

* Executor and exceptions refactor wip wip

* Fixing all_insts auto tests

* Visited and generate testcase now at manticore api level

* Aggregating state statistics into executor statistics

* Wip refactoring

* Executor and exceptions refactor wip wip

* Fixing all_insts auto tests

* Visited and generate testcase now at manticore api level

* Aggregating state statistics into executor statistics

* forwarding events wip

* state setstate fix and setup_stack merge fix

* will_terminate_state fix and tests skipped

* Update all ConcretizeRegister and ConcretizeMemory

* Exceptions are crazy crazy crazy

* fix last merge

* Merge merge until it pass

* Instructions count default to 0

* will/did execute/emulate

* Delayed keybpoard interrupt now shutdowns nicely

* fix auto test generator x86

* Undo bad merge

* utterly hopeless

* basic working

* Fix merge bugs and github comments

* Remove unnecesary comment - github comments

* trace_item not used there

* model-platform and system.py fixed

* backup/restore to store/load -- cpu.instruction property

* Slightly better did/will naming and dynamic signal forwarding

* platform.constraints and cpu.instruction as properties

* Fix forward signals getattr

* set las decoded pc at decode_instruction() / reenable instruction_cache

* Signals name convention: did/will/on

* Forward normal signals

* Maintain last decoded pc in abstractcpu

* Changed context manager so it just wont raise interrupt

* Decree now forwards signals and sets constraints

* linux.SymbolicFile does not need to maintain constraints

* remove debbug print

* Assimilating some PR commets

* size_total == size

* better merge of manticore.py

* typo

* Forwarding only specified objects in signal arguments

* Fix few broken tests

* revert + merge

* remove some unused stuff from manticore()

* manticore context <-> executor context

* manticore context <-> executor context2

* context context context

* forgotten return

* Fix basix.arm

* arm bitwise fix

* fix context

* Comment 1

* Comment 2

* Comment 3

* Comment 4

* Comment 5

* Comment 6

* Fix (still needs refactor but it works) profiling

* Fix (still needs refactor but it works) profiling

* The forgotten bit

* Update tests to reflect current output

* Verbosity fix

* Fix verbosity test
2017-06-26 18:06:18 -03:00

1401 lines
44 KiB
Python

import unittest
import struct
from functools import wraps
from manticore.core.cpu.arm import Armv7Cpu as Cpu, Mask, Interruption
from manticore.core.cpu.abstractcpu import ConcretizeRegister
from manticore.core.memory import ConcretizeMemory, Memory32, SMemory32
from manticore.core.state import State
from manticore.core.smtlib import BitVecVariable, ConstraintSet
from manticore.platforms import linux
from manticore.utils.emulate import UnicornEmulator
from capstone.arm import *
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM)
import logging
logger = logging.getLogger("ARM_TESTS")
__doc__ = '''
Test the Unicorn emulation stub. Armv7UnicornInstructions includes all
semantics from ARM tests to ensure that they match. UnicornConcretization tests
to make sure symbolic values get properly concretized.
'''
def assemble(asm):
ords = ks.asm(asm)[0]
if not ords:
raise Exception('bad assembly: {}'.format(asm))
return ''.join(map(chr, ords))
def emulate_next(cpu):
'Read the next instruction and emulate it with Unicorn '
cpu.decode_instruction(cpu.PC)
emu = UnicornEmulator(cpu)
emu.emulate(cpu.instruction)
def itest(asm):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asm)
emulate_next(self.cpu)
assertions_func(self)
return wrapper
return instr_dec
def itest_setregs(*preds):
def instr_dec(custom_func):
@wraps(custom_func)
def wrapper(self):
for p in preds:
dest, src = p.split('=')
try:
src = int(src, 0)
except:
pass
self.rf.write(dest.upper(), src)
custom_func(self)
return wrapper
return instr_dec
def itest_custom(asm):
def instr_dec(custom_func):
@wraps(custom_func)
def wrapper(self):
self._setupCpu(asm)
custom_func(self)
return wrapper
return instr_dec
class Armv7UnicornInstructions(unittest.TestCase):
'''
Import all of the tests from ARM, but execute with Unicorn to verify that
all semantics match.
'''
_multiprocess_can_split_ = True
def setUp(self):
self.cpu = Cpu(Memory32())
self.mem = self.cpu.memory
self.rf = self.cpu.regfile
def _setupCpu(self, asm):
self.code = self.mem.mmap(0x1000, 0x1000, 'rwx')
self.data = self.mem.mmap(0xd000, 0x1000, 'rw')
self.stack = self.mem.mmap(0xf000, 0x1000, 'rw')
start = self.code + 4
self.mem.write(start, assemble(asm))
self.rf.write('PC', start)
self.rf.write('SP', self.stack + 0x1000)
def _checkFlagsNZCV(self, n, z, c, v):
self.assertEqual(self.rf.read('APSR_N'), n)
self.assertEqual(self.rf.read('APSR_Z'), z)
self.assertEqual(self.rf.read('APSR_C'), c)
self.assertEqual(self.rf.read('APSR_V'), v)
# MOV
@itest("mov r0, 0x0")
def test_mov_imm_min(self):
self.assertEqual(self.rf.read('R0'), 0x0)
@itest("mov r0, 42")
def test_mov_imm_norm(self):
self.assertEqual(self.rf.read('R0'), 42)
@itest("mov r0, 0x100")
def test_mov_imm_modified_imm_min(self):
self.assertEqual(self.rf.read('R0'), 0x100)
@itest("mov r0, 0xff000000")
def test_mov_imm_modified_imm_max(self):
self.assertEqual(self.rf.read('R0'), 0xff000000)
@itest_custom("mov r0, r1")
def test_mov_immreg(self):
self.rf.write('R1', 0)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0)
@itest_custom("mov r0, r1")
def test_mov_immreg1(self):
self.rf.write('R1', 2 ** 32)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0)
@itest_custom("mov r0, r1")
def test_mov_immreg2(self):
self.rf.write('R1', 0xffffffff)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0xffffffff)
@itest_custom("mov r0, r1")
def test_mov_immreg3(self):
self.rf.write('R1', 42)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 42)
# MOVW
@itest("movw r0, 0")
def test_movw_imm_min(self):
self.assertEqual(self.rf.read('R0'), 0x0)
@itest("movw r0, 0xffff")
def test_movw_imm_max(self):
self.assertEqual(self.rf.read('R0'), 0xffff)
# MOVS
@itest_custom("movs r0, 0")
def test_movs_imm_min(self):
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0)
self._checkFlagsNZCV(0, 1, pre_c, pre_v)
@itest_custom("movs r0, 42")
def test_movs_imm_norm(self):
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 42)
self._checkFlagsNZCV(0, 0, pre_c, pre_v)
@itest_custom("movs r0, 0x100")
def test_movs_imm_modified_imm_min(self):
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0x100)
self._checkFlagsNZCV(0, 0, pre_c, pre_v)
@itest_custom("movs r0, 0xff000000")
def test_movs_imm_modified_imm_max(self):
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0xff000000)
self._checkFlagsNZCV(1, 0, 1, pre_v)
@itest_custom("movs r0, 0x0e000000")
def test_movs_imm_modified_imm_sans_carry(self):
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0x0e000000)
self._checkFlagsNZCV(0, 0, 0, pre_v)
@itest_custom("movs r0, r1")
def test_movs_reg(self):
self.rf.write('R1', 0)
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0)
self._checkFlagsNZCV(0, 1, pre_c, pre_v)
@itest_custom("movs r0, r1")
def test_movs_reg1(self):
self.rf.write('R1', 2 ** 32)
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 0)
self._checkFlagsNZCV(0, 1, pre_c, pre_v)
@itest_custom("movs r0, r1")
def test_movs_reg2(self):
self.rf.write('R1', 2 ** 32 - 1)
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 2 ** 32 - 1)
self._checkFlagsNZCV(1, 0, pre_c, pre_v)
@itest_custom("movs r0, r1")
def test_movs_reg3(self):
self.rf.write('R1', 42)
pre_c = self.rf.read('APSR_C')
pre_v = self.rf.read('APSR_V')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R0'), 42)
self._checkFlagsNZCV(0, 0, pre_c, pre_v)
# ADD
@itest_custom("add r3, r1, 55")
def test_add_imm_norm(self):
self.rf.write('R1', 44)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 99)
@itest_custom("add r3, r1, 0x100")
def test_add_imm_mod_imm_min(self):
self.rf.write('R1', 44)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 44 + 0x100)
@itest_custom("add r3, r1, 0xff000000")
def test_add_imm_mod_imm_max(self):
self.rf.write('R1', 44)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 44 + 0xff000000)
@itest_custom("add r3, r1, 0x1000000")
def test_add_imm_carry(self):
self.rf.write('R1', 0xff000001)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 1)
@itest_custom("add r3, r1, 0x1")
def test_add_imm_overflow(self):
self.rf.write('R1', (2 ** 31 - 1))
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 0x80000000)
@itest_custom("add r3, r1, r2")
def test_add_reg_norm(self):
self.rf.write('R1', 44)
self.rf.write('R2', 55)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 99)
@itest_custom("add r3, r1, r2")
def test_add_reg_mod_imm_min(self):
self.rf.write('R1', 44)
self.rf.write('R2', 0x100)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 44 + 0x100)
@itest_custom("add r3, r1, r2")
def test_add_reg_mod_imm_max(self):
self.rf.write('R1', 44)
self.rf.write('R2', 0xff000000)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 44 + 0xff000000)
@itest_custom("add r3, r1, r2")
def test_add_reg_carry(self):
self.rf.write('R1', 0x1000000)
self.rf.write('R2', 0xff000001)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 1)
@itest_custom("add r3, r1, r2")
def test_add_reg_overflow(self):
self.rf.write('R1', (2 ** 31 - 1))
self.rf.write('R2', 1)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), (1 << 31))
@itest_custom("add r3, r1, r2, lsl #3")
def test_add_reg_sft_lsl(self):
self.rf.write('R1', 0x0)
self.rf.write('R2', 0x1)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), (1 << 3))
@itest_custom("add r3, r1, r2, lsr #3")
def test_add_reg_sft_lsr(self):
self.rf.write('R1', 0x0)
self.rf.write('R2', 0x8)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x80000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x40000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x8)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x3)
emulate_next(self.cpu)
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):
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x3)
emulate_next(self.cpu)
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('APSR_C', 0x0)
self.rf.write('R1', 0x0)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
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('APSR_C', 0x1)
self.rf.write('R1', 0x0)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x1)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x8)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x80000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x40000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x8)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R4', 0x3)
self.rf.write('R2', 0x3)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('APSR_C', 0x0)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('APSR_C', 0x1)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
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('R1', 44)
emulate_next(self.cpu)
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('R1', 44)
emulate_next(self.cpu)
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('R1', 44)
emulate_next(self.cpu)
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('R1', 0xff000001)
emulate_next(self.cpu)
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('R1', 0x80000001)
emulate_next(self.cpu)
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('R1', (2 ** 31 - 1))
emulate_next(self.cpu)
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('R3', 0)
emulate_next(self.cpu)
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('R1', 44)
self.rf.write('R2', 55)
emulate_next(self.cpu)
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('R1', 44)
self.rf.write('R2', 0x100)
emulate_next(self.cpu)
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('R1', 44)
self.rf.write('R2', 0xff000000)
emulate_next(self.cpu)
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('R1', 0x1000000)
self.rf.write('R2', 0xff000001)
emulate_next(self.cpu)
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('R1', (2 ** 31 - 1))
self.rf.write('R2', 1)
emulate_next(self.cpu)
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('R1', 0x80000001)
self.rf.write('R2', 0x80000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x0)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x80000000)
emulate_next(self.cpu)
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('R1', 0x0)
self.rf.write('R2', 0x40000000)
emulate_next(self.cpu)
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('APSR_C', 0x0)
self.rf.write('R1', 0x0)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
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('APSR_C', 0x1)
self.rf.write('R1', 0x0)
self.rf.write('R2', 2 ** 32 - 1)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1)
self._checkFlagsNZCV(1, 0, 0, 0)
# LDR imm
@itest_custom("ldr r1, [sp]")
def test_ldr_imm_off_none(self):
self.cpu.stack_push(42)
emulate_next(self.cpu)
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)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 42)
@itest_custom("ldr r1, [sp, #-4]")
def test_ldr_imm_off_neg(self):
self.cpu.stack_push(42)
self.cpu.stack_push(41)
self.cpu.STACK += 4
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 41)
@itest_custom("ldr r1, [sp, #4]!")
def test_ldr_imm_preind_pos(self):
self.cpu.stack_push(42)
self.cpu.stack_push(41)
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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):
self.cpu.stack_push(42)
self.cpu.stack_push(41)
self.cpu.STACK += 4
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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
emulate_next(self.cpu)
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
emulate_next(self.cpu)
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('R2', 4)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 42)
@itest_custom("ldr r1, [sp, -r2]")
def test_ldr_reg_off_neg(self):
self.cpu.regfile.write('R2', 4)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
self.cpu.STACK += 4
emulate_next(self.cpu)
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('R2', 1)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
self.cpu.stack_push(40)
emulate_next(self.cpu)
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('R2', 1)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
self.cpu.STACK += 8
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 48)
@itest_custom("ldr r1, [sp, r2]!")
def test_ldr_reg_preind(self):
self.cpu.regfile.write('R2', 4)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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('R2', 1)
self.cpu.stack_push(42)
self.cpu.stack_push(48)
self.cpu.STACK += 8
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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('R2', 4)
self.cpu.stack_push(42)
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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('R2', 1)
self.cpu.stack_push(42)
pre_stack = self.cpu.STACK
emulate_next(self.cpu)
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
emulate_next(self.cpu)
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):
vals = [0x01, 0x55, 0xAA]
for v in vals:
self.cpu.stack_push(v)
emulate_next(self.cpu)
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")
def test_push_one_reg(self):
emulate_next(self.cpu)
self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3))
@itest_custom("push {r1, r2, r3}")
@itest_setregs("R1=3", "R2=0x55", "R3=0xffffffff")
def test_push_multi_reg(self):
pre_sp = self.cpu.STACK
emulate_next(self.cpu)
sp = self.cpu.STACK
self.assertEqual(self.rf.read('SP'), pre_sp - (3 * 4))
self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3))
self.assertEqual(self.cpu.read_int(sp + 4, self.cpu.address_bit_size), 0x55)
self.assertEqual(self.cpu.read_int(sp + 8, self.cpu.address_bit_size), 0xffffffff)
@itest_custom("str SP, [R1]")
@itest_setregs("R1=0xd000")
def test_str_basic(self):
r1 = self.rf.read('R1')
sp = self.rf.read('SP')
emulate_next(self.cpu)
dr1 = self.cpu.read_int(r1, self.cpu.address_bit_size)
self.assertEqual(sp, dr1)
@itest_custom("str R1, [R2, R3]")
@itest_setregs("R1=34", "R2=0xD000", "R3=8")
def test_str_index(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
r3 = self.rf.read('R3')
emulate_next(self.cpu)
retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size)
self.assertEqual(retrieved, r1)
@itest_custom("str R1, [R2, R3, LSL #3]")
@itest_setregs("R1=34", "R2=0xD000", "R3=1")
def test_str_index_w_shift(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
r3 = self.rf.read('R3')
r3 = r3 << 3
emulate_next(self.cpu)
retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size)
self.assertEqual(retrieved, r1)
@itest_custom("str R1, [R2], #3")
@itest_setregs("R1=34", "R2=0xD000")
def test_str_postindex(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
emulate_next(self.cpu)
# check store results
data = self.cpu.read_int(r2, self.cpu.address_bit_size)
self.assertEqual(data, r1)
# check writeback results
new_r2 = self.rf.read('R2')
self.assertEqual(new_r2, r2 + 3)
@itest_custom("str R1, [R2, #3]!")
@itest_setregs("R1=34", "R2=0xD000")
def test_str_index_writeback(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
emulate_next(self.cpu)
# check store results
data = self.cpu.read_int(r2 + 3, self.cpu.address_bit_size)
self.assertEqual(data, r1)
# check writeback results
new_r2 = self.rf.read('R2')
self.assertEqual(new_r2, r2 + 3)
# BL
@itest_custom("bl 0x170")
def test_bl(self):
pre_pc = self.rf.read('PC')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('PC'), pre_pc + 0x170)
self.assertEqual(self.rf.read('LR'), pre_pc + 4)
@itest_custom("bl #-4")
def test_bl_neg(self):
pre_pc = self.rf.read('PC')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('PC'), pre_pc - 4)
self.assertEqual(self.rf.read('LR'), pre_pc + 4)
# CMP
@itest_setregs("R0=3")
@itest("cmp r0, 3")
def test_cmp_eq(self):
self._checkFlagsNZCV(0, 1, 1, 0)
@itest_setregs("R0=3")
@itest("cmp r0, 5")
def test_cmp_lt(self):
self._checkFlagsNZCV(1, 0, 0, 0)
@itest_setregs("R0=3")
@itest("cmp r0, 2")
def test_cmp_gt(self):
self._checkFlagsNZCV(0, 0, 1, 0)
@itest_setregs("R0=0")
@itest("cmp r0, 0")
def test_cmp_carry(self):
self._checkFlagsNZCV(0, 1, 1, 0)
@itest_setregs("R0=0x40000000")
@itest("cmp r0, 0xa0000000")
def test_cmp_ovf(self):
self._checkFlagsNZCV(1, 0, 0, 1)
@itest_setregs("R0=0x80000000")
@itest("cmp r0, 0x40000000")
def test_cmp_carry_ovf(self):
self._checkFlagsNZCV(0, 0, 1, 1)
# CLZ
@itest_custom("clz r1, r2")
@itest_setregs("R2=0xFFFF")
def test_clz_sixteen_zeroes(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 16)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0")
def test_clz_all_zero(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), self.cpu.address_bit_size)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0xffffffff")
def test_clz_no_leading_zeroes(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0x7fffffff")
def test_clz_one_leading_zero(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 1)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0x7f7fffff")
def test_clz_lead_zero_then_more_zeroes(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 1)
@itest_custom("sub r3, r1, r2")
@itest_setregs("R1=4", "R2=2")
def test_sub_basic(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 2)
@itest_custom("sub r3, r1, #5")
@itest_setregs("R1=10")
def test_sub_imm(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 5)
@itest_custom("sbc r3, r1, #5")
@itest_setregs("R1=10")
def test_sbc_imm(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R3'), 4)
@itest_custom("ldm sp, {r1, r2, r3}")
def test_ldm(self):
self.cpu.stack_push(0x41414141)
self.cpu.stack_push(2)
self.cpu.stack_push(42)
pre_sp = self.cpu.STACK
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 42)
self.assertEqual(self.rf.read('R2'), 2)
self.assertEqual(self.rf.read('R3'), 0x41414141)
self.assertEqual(self.cpu.STACK, pre_sp)
@itest_custom("ldm sp!, {r1, r2, r3}")
def test_ldm_wb(self):
self.cpu.stack_push(0x41414141)
self.cpu.stack_push(2)
self.cpu.stack_push(42)
pre_sp = self.cpu.STACK
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 42)
self.assertEqual(self.rf.read('R2'), 2)
self.assertEqual(self.rf.read('R3'), 0x41414141)
self.assertEqual(self.cpu.STACK, pre_sp + 12)
@itest_setregs("R1=2", "R2=42", "R3=0x42424242")
@itest_custom("stm sp, {r1, r2, r3}")
def test_stm(self):
self.cpu.STACK -= 12
pre_sp = self.cpu.STACK
emulate_next(self.cpu)
self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2)
self.assertEqual(self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42)
self.assertEqual(self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size),
0x42424242)
self.assertEqual(self.cpu.STACK, pre_sp)
@itest_setregs("R1=2", "R2=42", "R3=0x42424242")
@itest_custom("stm sp!, {r1, r2, r3}")
def test_stm_wb(self):
self.cpu.STACK -= 12
pre_sp = self.cpu.STACK
emulate_next(self.cpu)
self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2)
self.assertEqual(self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42)
self.assertEqual(self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size),
0x42424242)
self.assertEqual(self.cpu.STACK, pre_sp + 12)
@itest_custom("stmib r3, {r2, r4}")
@itest_setregs("R1=1", "R2=2", "R4=4", "R3=0xd100")
def test_stmib_basic(self):
emulate_next(self.cpu)
addr = self.rf.read('R3')
self.assertEqual(self.cpu.read_int(addr + 4, self.cpu.address_bit_size), 2)
self.assertEqual(self.cpu.read_int(addr + 8, self.cpu.address_bit_size), 4)
@itest_custom("bx r1")
@itest_setregs("R1=0x1008")
def test_bx_basic(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('PC'), 0x1008)
@itest_custom("bx r1")
@itest_setregs("R1=0x1009")
def test_bx_thumb(self):
pre_pc = self.rf.read('PC')
emulate_next(self.cpu)
self.assertEqual(self.rf.read('PC'), pre_pc + 4)
# ORR
@itest_custom("orr r2, r3, #5")
@itest_setregs("R3=0x1000")
def test_orr_imm(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x1005)
@itest_custom("orrs r2, r3")
@itest_setregs("R2=0x5", "R3=0x80000000")
def test_orrs_imm_flags(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x80000005)
self.assertEqual(self.rf.read('APSR_N'), True)
@itest_custom("orr r2, r3")
@itest_setregs("R2=0x5", "R3=0x80000000")
def test_orr_reg_w_flags(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x80000005)
# self.assertEqual(self.rf.read('APSR_N'), 1)
@itest_custom("orr r2, r3, r4")
@itest_setregs("R3=0x5", "R4=0x80000000")
def test_orr_reg_two_op(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x80000005)
# self.assertEqual(self.rf.read('APSR_N'), 1)
@itest_custom("orr r2, r3, r4, LSL #4")
@itest_setregs("R3=0x5", "R4=0xF")
def test_orr_reg_two_op_shifted(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0xF5)
# EOR
@itest_custom("eor r2, r3, #5")
@itest_setregs("R3=0xA")
def test_eor_imm(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0xF)
@itest_custom("eors r2, r3")
@itest_setregs("R2=0xAA", "R3=0x80000000")
def test_eors_imm_flags(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x800000AA)
self.assertEqual(self.rf.read('APSR_N'), True)
@itest_custom("eors r2, r3")
@itest_setregs("R2=0x5", "R3=0x80000005")
def test_eor_reg_w_flags(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x80000000)
self.assertEqual(self.rf.read('APSR_N'), 1)
@itest_custom("eor r2, r3, r4")
@itest_setregs("R3=0x80000005", "R4=0x80000005")
def test_eor_reg_two_op(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0)
@itest_custom("eor r2, r3, r4, LSL #4")
@itest_setregs("R3=0x55", "R4=0x5")
def test_eor_reg_two_op_shifted(self):
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R2'), 0x5)
# LDRH - see also LDR tests
@itest_custom("ldrh r1, [sp]")
def test_ldrh_imm_off_none(self):
self.cpu.stack_push(0x41410041)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x41)
@itest_custom("ldrh r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrh_reg_off(self):
self.cpu.stack_push(0x41410041)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x41)
# LDRSH - see also LDR tests
@itest_custom("ldrsh r1, [sp]")
def test_ldrsh_imm_off_none_neg(self):
self.cpu.stack_push(0x2ff0f)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0xffffff0f)
@itest_custom("ldrsh r1, [sp]")
def test_ldrsh_imm_off_none_pos(self):
self.cpu.stack_push(0xff0fff)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x0fff)
@itest_custom("ldrsh r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrsh_reg_off_neg(self):
self.cpu.stack_push(0x2ff0f)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0xffffff0f)
@itest_custom("ldrsh r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrsh_reg_off_pos(self):
self.cpu.stack_push(0xff0fff)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x0fff)
# LDRB - see also LDR tests
@itest_custom("ldrb r1, [sp]")
def test_ldrb_imm_off_none(self):
self.cpu.stack_push(0x41)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x41)
@itest_custom("ldrb r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrb_reg_off(self):
self.cpu.stack_push(0x41)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0x41)
# LDRSB - see also LDR tests
@itest_custom("ldrsb r1, [sp]")
def test_ldrsb_imm_off_none_neg(self):
self.cpu.stack_push(0x2ff)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), Mask(32))
@itest_custom("ldrsb r1, [sp]")
def test_ldrsb_imm_off_none_pos(self):
self.cpu.stack_push(0xff0f)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0xf)
@itest_custom("ldrsb r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrsb_reg_off_neg(self):
self.cpu.stack_push(0x2ff)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), Mask(32))
@itest_custom("ldrsb r1, [sp, r2]")
@itest_setregs("R2=4")
def test_ldrsb_reg_off_pos(self):
self.cpu.stack_push(0xff0f)
self.cpu.stack_push(48)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('R1'), 0xf)
# TST
@itest_setregs("R1=1", "R3=0")
@itest("tst r3, r1")
def test_tst(self):
self._checkFlagsNZCV(0, 1, 0, 0)
# AND
@itest_setregs("R2=5")
@itest("and r2, r2, #1")
def test_and_imm(self):
self.assertEqual(self.rf.read('R2'), 1)
@itest_setregs("R1=5", "R2=3")
@itest("and r1, r1, r2")
def test_and_reg(self):
self.assertEqual(self.rf.read('R1'), 3 & 5)
@itest_setregs("R1=5", "R2=3", "APSR_C=1")
@itest("and r1, r1, r2")
def test_and_reg_carry(self):
self.assertEqual(self.rf.read('R1'), 3 & 5)
self.assertEqual(self.rf.read('APSR_C'), 1)
# svc
def test_svc(self):
with self.assertRaises(Interruption):
self._setupCpu("svc #0")
emulate_next(self.cpu)
# lsl
@itest_setregs("R3=0x11")
@itest("lsls r4, r3, 1")
def test_lsl_imm_min(self):
self.assertEqual(self.rf.read('R4'), 0x11 << 1)
self._checkFlagsNZCV(0, 0, 0, 0)
@itest_setregs("R3=0x11")
@itest("lsls r4, r3, 31")
def test_lsl_imm_max(self):
self.assertEqual(self.rf.read('R4'), 1 << 31)
self._checkFlagsNZCV(1, 0, 0, 0)
@itest_setregs("R3=0x11", "R2=0xff01")
@itest("lsls r4, r3, r2")
def test_lsl_reg_min(self):
self.assertEqual(self.rf.read('R4'), 0x11 << 1)
self._checkFlagsNZCV(0, 0, 0, 0)
@itest_setregs("R3=0x11", "R2=0xff1f")
@itest("lsls r4, r3, r2")
def test_lsl_reg_max(self):
self.assertEqual(self.rf.read('R4'), 0x1 << 31)
self._checkFlagsNZCV(1, 0, 0, 0)
# lsr
@itest_setregs("R0=0x1000", "R2=3")
@itest("lsr r0, r0, r2")
def test_lsr_reg(self):
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('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('R2'), 2)
def test_flag_state_continuity(self):
'''If an instruction only partially updates flags, cpu.setFlags should
ensure unupdated flags are preserved.
For example:
r1 = 2**31 - 1
add r2, r1, 0x1 // overflow = 1
mov r1, 1
mov r3, 0
tst r3, r1 // does not change overflow flag
// ovf should still be 1
'''
self.rf.write('R1', (2 ** 31 - 1))
self._setupCpu("adds r2, r1, #0x1")
emulate_next(self.cpu)
self.rf.write('R1', 1)
self.rf.write('R3', 0)
self.mem.write(self.cpu.PC, assemble("tst r3, r1"))
emulate_next(self.cpu)
self._checkFlagsNZCV(0, 1, 0, 1)
@itest_setregs("R1=30", "R2=10")
@itest("MUL R1, R2")
def test_mul_reg(self):
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('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('R1'), 157)
@itest_setregs("R1=0xFF")
@itest("BIC R2, R1, #0x10")
def test_bic_reg_imm(self):
self.assertEqual(self.rf.read('R2'), 0xEF)
@itest_setregs("R1=0x1008")
@itest("BLX R1")
def test_blx_reg(self):
self.assertEqual(self.rf.read('PC'), 0x1008)
self.assertEqual(self.rf.read('LR'), 0x1008)
@itest_setregs("R1=0x1009")
@itest("BLX R1")
def test_blx_reg_thumb(self):
self.assertEqual(self.rf.read('PC'), 0x1008)
self.assertEqual(self.rf.read('LR'), 0x1008)
@itest_setregs("R1=0xffffffff", "R2=2")
@itest("UMULLS R1, R2, R1, R2")
def test_umull(self):
mul = 0xffffffff * 2
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('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('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('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)
class UnicornConcretization(unittest.TestCase):
'''
Test the ability of Unicorn-based emulation to correctly request certain
locations to be concretized.
'''
cpu = None
state = None
@classmethod
def get_state(cls):
if cls.cpu is None:
constraints = ConstraintSet()
platform = linux.SLinux('/bin/ls')
cls.state = State(constraints, platform)
cls.cpu = platform._mk_proc('armv7')
return (cls.cpu, cls.state)
def setUp(self):
self.cpu, self.state = self.__class__.get_state()
self.mem = self.cpu.memory
self.rf = self.cpu.regfile
def _setupCpu(self, asm):
self.code = self.mem.mmap(0x1000, 0x1000, 'rwx')
self.data = self.mem.mmap(0xd000, 0x1000, 'rw')
self.stack = self.mem.mmap(0xf000, 0x1000, 'rw')
start = self.code + 4
self.mem.write(start, assemble(asm))
self.rf.write('PC', start)
self.rf.write('SP', self.stack + 0xffc)
@itest_custom("ldr r1, [sp]")
def test_load_symbolic(self):
self.cpu.STACK -= 4
val = self.state.symbolicate_buffer('++++', wildcard='+')
self.cpu.write_bytes(self.rf.read('SP'), val)
with self.assertRaises(ConcretizeMemory) as e:
emulate_next(self.cpu)
@itest_custom("ldr r1, [sp]")
def test_load_symbolic_correct_address(self):
self.cpu.STACK -= 4
val = self.state.symbolicate_buffer('++++', wildcard='+')
sp = self.rf.read('SP')
self.cpu.write_bytes(sp, val)
try:
emulate_next(self.cpu)
# Make sure we raise
self.assertFalse(True)
except ConcretizeMemory as e:
sp = self.rf.read('SP')
self.assertTrue(e.address in range(sp, sp+len(val)))
@itest_custom("mov r1, r2")
def test_load_symbolic_from_register(self):
val = self.state.new_symbolic_value(32)
self.rf.write('R2', val)
try:
emulate_next(self.cpu)
# Make sure we raise
self.assertFalse(True)
except ConcretizeRegister as e:
self.assertEqual(e.reg_name, 'R2')
def test_arm_constant(self):
self.code = self.mem.mmap(0x1000, 0x1000, 'rwx')
self.data = self.mem.mmap(0xd000, 0x1000, 'rw')
self.stack = self.mem.mmap(0xf000, 0x1000, 'rw')
start = self.code + 4
constant = 0x42424242
asm = '''
ldr r0, [pc, #-4]
'''
code = assemble(asm)
code += '\x78\x56\x34\x12'
self.mem.write(start, code)
self.rf.write('PC', start)
self.rf.write('SP', self.stack + 0x1000)
emulate_next(self.cpu)
self.assertEqual(self.rf.read('PC'), self.code+8)
self.assertEqual(self.rf.read('R0'), 0x12345678)