manticore/tests/test_armv7cpu.py
Yan Ivnitskiy 394401e3f4
Fix ARMv7's ADD (#769)
* Fix armv7's ADD
2018-02-23 18:07:49 -05:00

1669 lines
53 KiB
Python

import unittest
import struct
from functools import wraps
from manticore.core.cpu.arm import Armv7Cpu as Cpu, Mask, Interruption
from manticore.core.memory import Memory32, SMemory32
from manticore.core.smtlib import *
from manticore.core.state import Concretize
from capstone.arm import *
from capstone import CS_MODE_THUMB, CS_MODE_ARM
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM)
ks_thumb = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
import logging
logger = logging.getLogger("ARM_TESTS")
def assemble(asm, mode=CS_MODE_ARM):
if CS_MODE_ARM == mode:
ords = ks.asm(asm)[0]
elif CS_MODE_THUMB == mode:
ords = ks_thumb.asm(asm)[0]
else:
raise Exception('bad processor mode for assembly: {}'.format(mode))
if not ords:
raise Exception('bad assembly: {}'.format(asm))
return ''.join(map(chr, ords))
class Armv7CpuTest(unittest.TestCase):
_multiprocess_can_split_ = True
def setUp(self):
cs = ConstraintSet()
self.c = Cpu(SMemory32(cs))
self.rf = self.c.regfile
self._setupStack()
def _setupStack(self):
self.stack = self.c.memory.mmap(0xf000, 0x1000, 'rw')
self.rf.write('SP', self.stack + 0x1000)
def test_rd(self):
self.assertEqual(self.rf.read('R0'), 0)
def test_rd2(self):
self.c.STACK = 0x1337
self.assertEqual(self.rf.read('SP'), 0x1337)
def test_stack_set_get(self):
self.c.STACK = 0x1337
self.assertEqual(self.c.STACK, 0x1337)
def test_rd3(self):
self.c.STACK = 0x1337 - 1
self.assertEqual(self.rf.read('SP'), 0x1336)
def test_rd4(self):
self.c.STACK = 0x1337 + 1
self.assertEqual(self.rf.read('SP'), 0x1338)
def test_stack_push(self):
self.c.stack_push(42)
self.c.stack_push(44)
self.assertItemsEqual(self.c.read(self.c.STACK, 4), '\x2c\x00\x00\x00')
self.assertItemsEqual(self.c.read(self.c.STACK + 4, 4), '\x2a\x00\x00\x00')
def test_stack_pop(self):
v = 0x55
v_bytes = struct.pack('<I', v)
self.c.stack_push(v)
val = self.c.stack_pop()
self.assertItemsEqual(self.c.read(self.c.STACK - 4, 4), v_bytes)
def test_stack_peek(self):
self.c.stack_push(42)
self.assertItemsEqual(self.c.stack_peek(), '\x2a\x00\x00\x00')
def test_readwrite_int(self):
self.c.STACK -= 4
self.c.write_int(self.c.STACK, 0x4242, 32)
self.assertEqual(self.c.read_int(self.c.STACK), 0x4242)
def itest_failing(asm):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asm)
self.cpu.instruction = "\x00\x00\x00\x00"
# self.cpu.execute()
assertions_func(self)
return wrapper
return instr_dec
def itest(asm):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asm)
self.cpu.execute()
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
def itest_thumb(asm):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asm, mode=CS_MODE_THUMB)
self.cpu.execute()
assertions_func(self)
return wrapper
return instr_dec
def itest_multiple(asms):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asms, mode=CS_MODE_ARM, multiple_insts=True)
for i in range(len(asms)):
self.cpu.execute()
assertions_func(self)
return wrapper
return instr_dec
def itest_thumb_multiple(asms):
def instr_dec(assertions_func):
@wraps(assertions_func)
def wrapper(self):
self._setupCpu(asms, mode=CS_MODE_THUMB, multiple_insts=True)
for i in range(len(asms)):
self.cpu.execute()
assertions_func(self)
return wrapper
return instr_dec
class Armv7CpuInstructions(unittest.TestCase):
def setUp(self):
cs = ConstraintSet()
self.cpu = Cpu(SMemory32(cs))
self.mem = self.cpu.memory
self.rf = self.cpu.regfile
def _setupCpu(self, asm, mode=CS_MODE_ARM, multiple_insts=False):
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
if multiple_insts:
offset = 0
for asm_single in asm:
asm_inst = assemble(asm_single, mode)
self.mem.write(start+offset, asm_inst)
offset += len(asm_inst)
else:
self.mem.write(start, assemble(asm, mode))
self.rf.write('PC', start)
self.rf.write('SP', self.stack + 0x1000)
self.cpu.mode = mode
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)
self.cpu.execute()
self.assertEqual(self.rf.read('R0'), 0)
@itest_custom("mov r0, r1")
def test_mov_immreg1(self):
self.rf.write('R1', 2 ** 32)
self.cpu.execute()
self.assertEqual(self.rf.read('R0'), 0)
@itest_custom("mov r0, r1")
def test_mov_immreg2(self):
self.rf.write('R1', 0xffffffff)
self.cpu.execute()
self.assertEqual(self.rf.read('R0'), 0xffffffff)
@itest_custom("mov r0, r1")
def test_mov_immreg3(self):
self.rf.write('R1', 42)
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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))
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
self.assertEqual(self.rf.read('R3'), 0x60000000)
@itest_setregs("R3=0xfffffff6", "R4=10")
@itest_thumb("adcs r3, r4")
def test_thumb_adc_basic(self):
self.assertEqual(self.rf.read('R3'), 0)
@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('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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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))
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1)
self._checkFlagsNZCV(1, 0, 0, 0)
@itest_setregs("R0=0")
@itest_thumb("adds r0, #4")
def test_adds_thumb_two_op(self):
self.assertEqual(self.rf.read('R0'), 4)
# UADD8
@itest_setregs("R2=0x00FF00FF", "R3=0x00010002")
@itest_thumb("uadd8 r2, r2, r3")
def test_uadd8(self):
self.assertEqual(self.rf.read('R2'), 1)
self.assertEqual(self.rf.read('APSR_GE'), 5)
# LDR imm
@itest_custom("ldr r1, [sp]")
def test_ldr_imm_off_none(self):
self.cpu.stack_push(42)
self.cpu.execute()
self.assertEqual(self.rf.read('R1'), 42)
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
@itest_custom("ldr pc, [sp]")
def test_ldr_imm_off_none_to_thumb(self):
self.cpu.stack_push(43)
self.cpu.execute()
self.assertEqual(self.rf.read('R15'), 42)
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
@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('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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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('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('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)
self.cpu.execute()
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
self.cpu.execute()
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)
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
self.assertEqual(self.rf.read('R1'), 42)
self.assertEqual(self.rf.read('SP'), pre_stack - 8)
@itest_custom("ldrd r2, [sp]")
def test_ldrd(self):
r2 = 0x41
r3 = 0x42
self.cpu.stack_push(r3)
self.cpu.stack_push(r2)
self.cpu.execute()
self.assertEqual(self.rf.read('R2'), r2)
self.assertEqual(self.rf.read('R3'), r3)
@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('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)
self.cpu.execute()
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):
self.cpu.execute()
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
self.cpu.execute()
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')
self.cpu.execute()
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')
self.cpu.execute()
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
self.cpu.execute()
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')
self.cpu.execute()
# 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')
self.cpu.execute()
# 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)
@itest_custom("strd R2, [R1]")
@itest_setregs("R1=0xD000", "R2=34", "R3=35")
def test_strd(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
r3 = self.rf.read('R3')
self.cpu.execute()
dr2 = self.cpu.read_int(r1, self.cpu.address_bit_size)
dr3 = self.cpu.read_int(r1+4, self.cpu.address_bit_size)
self.assertEqual(dr2, r2)
self.assertEqual(dr3, r3)
@itest_custom("str R2, [R1]")
@itest_setregs("R1=0xD000", "R2=34")
def test_str(self):
r1 = self.rf.read('R1')
r2 = self.rf.read('R2')
self.cpu.execute()
dr2 = self.cpu.read_int(r1, self.cpu.address_bit_size)
self.assertEqual(dr2, r2)
# BL
@itest_custom("bl 0x170")
def test_bl(self):
pre_pc = self.rf.read('PC')
self.cpu.execute()
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')
self.cpu.execute()
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):
self.cpu.execute()
self.assertEqual(self.rf.read('R1'), 16)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0")
def test_clz_all_zero(self):
self.cpu.execute()
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):
self.cpu.execute()
self.assertEqual(self.rf.read('R1'), 0)
@itest_custom("clz r1, r2")
@itest_setregs("R2=0x7fffffff")
def test_clz_one_leading_zero(self):
self.cpu.execute()
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):
self.cpu.execute()
self.assertEqual(self.rf.read('R1'), 1)
@itest_custom("sub r3, r1, r2")
@itest_setregs("R1=4", "R2=2")
def test_sub_basic(self):
self.cpu.execute()
self.assertEqual(self.rf.read('R3'), 2)
@itest_setregs("R3=0xE")
@itest_thumb("sub r3, #12")
def test_thumb_sub_basic(self):
self.assertEqual(self.rf.read('R3'), 2)
@itest_custom("sub r3, r1, #5")
@itest_setregs("R1=10")
def test_sub_imm(self):
self.cpu.execute()
self.assertEqual(self.rf.read('R3'), 5)
@itest_custom("sbc r3, r1, #5")
@itest_setregs("R1=10")
def test_sbc_imm(self):
self.cpu.execute()
self.assertEqual(self.rf.read('R3'), 4)
@itest_setregs("R0=0","R3=0xffffffff")
@itest_thumb("sbcs r0, r3")
def test_sbc_thumb(self):
self.assertEqual(self.rf.read('R0'), 0)
@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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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
self.cpu.execute()
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):
self.cpu.execute()
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):
self.cpu.execute()
self.assertEqual(self.rf.read('PC'), 0x1008)
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
@itest_custom("bx r1")
@itest_setregs("R1=0x1009")
def test_bx_thumb(self):
pre_pc = self.rf.read('PC')
self.cpu.execute()
self.assertEqual(self.rf.read('PC'), pre_pc + 4)
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
# ORR
@itest_custom("orr r2, r3, #5")
@itest_setregs("R3=0x1000")
def test_orr_imm(self):
self.cpu.execute()
self.assertEqual(self.rf.read('R2'), 0x1005)
@itest_setregs("R3=0x1000")
@itest_thumb("orr r3, #5")
def test_thumb_orr_imm(self):
self.assertEqual(self.rf.read('R3'), 0x1005)
@itest_custom("orrs r2, r3")
@itest_setregs("R2=0x5", "R3=0x80000000")
def test_orrs_imm_flags(self):
self.cpu.execute()
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):
self.cpu.execute()
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):
self.cpu.execute()
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):
self.cpu.execute()
self.assertEqual(self.rf.read('R2'), 0xF5)
# ORN
@itest_setregs("R2=0x0", "R5=0xFFFFFFFA")
@itest_thumb("orn r2, r2, r5")
def test_orn(self):
self.assertEqual(self.rf.read('R2'), 0x5)
# EOR
@itest_custom("eor r2, r3, #5")
@itest_setregs("R3=0xA")
def test_eor_imm(self):
self.cpu.execute()
self.assertEqual(self.rf.read('R2'), 0xF)
@itest_setregs("R3=0xA")
@itest_thumb("eor r3, #5")
def test_thumb_eor_imm(self):
self.assertEqual(self.rf.read('R3'), 0xF)
@itest_custom("eors r2, r3")
@itest_setregs("R2=0xAA", "R3=0x80000000")
def test_eors_imm_flags(self):
self.cpu.execute()
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):
self.cpu.execute()
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):
self.cpu.execute()
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):
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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)
self.cpu.execute()
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")
self.cpu.execute()
# 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)
@itest_setregs("R2=0xffffffff")
@itest("lsls r2, r2, #0x1f")
def test_lsl_imm_carry(self):
self.assertEqual(self.cpu.R2, 0x1 << 31)
self._checkFlagsNZCV(1, 0, 1, 0)
@itest_setregs("R5=1", "R6=2")
@itest_thumb("lsl.w r5, r6, #3")
def test_lslw_thumb(self):
'''thumb mode specific behavior'''
self.assertEqual(self.cpu.R5, 0x2 << 3)
# 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("R1=0", "R2=3")
@itest_thumb("lsrs r1, r2")
def test_thumb_lsrs(self):
self.assertEqual(self.cpu.R1, 0)
@itest_setregs("R5=0", "R6=16")
@itest_thumb("lsr.w R5, R6, #3")
def test_lsrw_thumb(self):
self.assertEqual(self.cpu.R5, 16>>3)
@itest_setregs("R5=0", "R6=16")
@itest_thumb("asr.w R5, R6, #3")
def test_asrw_thumb(self):
self.assertEqual(self.cpu.R5, 16>>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)
@itest_setregs("R6=2", "R8=0xfffffffe")
@itest("RSBS r8, r6, #0")
def test_rsbs_carry(self):
self.assertEqual(self.rf.read('R8'), 0xFFFFFFFE)
self._checkFlagsNZCV(1, 0, 0, 0)
def test_flag_state_continuity(self):
'''If an instruction only partially updates flags, cpu.set_flags 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")
self.cpu.execute()
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)
@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=0xFF")
@itest("BIC R1, #0x10")
def test_thumb_bic_reg_imm(self):
self.assertEqual(self.rf.read('R1'), 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)
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
@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)
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
@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)
@itest("dmb ish")
def test_dmb(self):
# This is a nop, ensure that the instruction exists
self.assertTrue(True)
@itest_custom("vldmia r1, {d8, d9, d10}")
def test_vldmia(self):
self.cpu.stack_push(20, 8)
self.cpu.stack_push(21, 8)
self.cpu.stack_push(22, 8)
self.cpu.R1 = self.cpu.SP
pre = self.cpu.R1
self.cpu.execute()
self.assertEqual(self.cpu.D8, 22)
self.assertEqual(self.cpu.D9, 21)
self.assertEqual(self.cpu.D10, 20)
self.assertEqual(self.cpu.R1, pre)
@itest_custom("vldmia r1!, {d8, d9, d10}")
def test_vldmia_wb(self):
pre = self.cpu.SP
self.cpu.stack_push(20, 8)
self.cpu.stack_push(21, 8)
self.cpu.stack_push(22, 8)
self.cpu.R1 = self.cpu.SP
self.cpu.execute()
self.assertEqual(self.cpu.D8, 22)
self.assertEqual(self.cpu.D9, 21)
self.assertEqual(self.cpu.D10, 20)
self.assertEqual(self.cpu.R1, pre)
@itest_setregs("R3=3")
@itest("movt R3, #9")
def test_movt(self):
self.assertEqual(self.cpu.R3, 0x90003)
@itest_custom("mrc p15, #0, r2, c13, c0, #3")
def test_mrc(self):
self.cpu.set_arm_tls(0x55555)
self.cpu.write_register('R2', 0)
self.cpu.execute()
self.assertEqual(self.cpu.R2, 0x55555)
@itest_setregs("R1=0x45", "R2=0x55555555")
@itest("uxtb r1, r2")
def test_uxtb(self):
self.assertEqual(self.cpu.R2, 0x55555555)
self.assertEqual(self.cpu.R1, 0x55)
@itest_setregs("R1=1","R2=0","R3=0","R4=0","R12=0x4141")
@itest_thumb_multiple(["cmp r1, #1", "itt ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
def test_itt_ne_noexec(self):
self.assertEqual(self.rf.read('R2'), 0)
self.assertEqual(self.rf.read('R3'), 0)
self.assertEqual(self.rf.read('R4'), 0x4141)
@itest_setregs("R1=0","R2=0","R3=0","R4=0","R12=0x4141")
@itest_thumb_multiple(["cmp r1, #1", "itt ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
def test_itt_ne_exec(self):
self.assertEqual(self.rf.read('R2'), 0x4141)
self.assertEqual(self.rf.read('R3'), 0x4141)
self.assertEqual(self.rf.read('R4'), 0x4141)
@itest_setregs("R1=0","R2=0","R3=0","R4=0","R12=0x4141")
@itest_thumb_multiple(["cmp r1, #1", "ite ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
def test_ite_ne_exec(self):
self.assertEqual(self.rf.read('R2'), 0x4141)
self.assertEqual(self.rf.read('R3'), 0x0)
self.assertEqual(self.rf.read('R4'), 0x4141)
@itest_setregs("R1=0","R2=0","R3=0","R4=0")
@itest_thumb_multiple(["cmp r1, #1", "itete ne", "mov r1, #1", "mov r2, #1", "mov r3, #1", "mov r4, #4"])
def test_itete_exec(self):
self.assertEqual(self.rf.read('R1'), 1)
self.assertEqual(self.rf.read('R2'), 0)
self.assertEqual(self.rf.read('R3'), 1)
self.assertEqual(self.rf.read('R4'), 0)
@itest_setregs("APSR_GE=3","R4=0","R5=0x01020304","R6=0x05060708")
@itest_thumb("sel r4, r5, r6")
def test_sel(self):
self.assertEqual(self.rf.read('R4'), 0x05060304)
@itest_setregs("R2=0","R1=0x01020304")
@itest("rev r2, r1")
def test_rev(self):
self.assertEqual(self.rf.read('R1'), 0x01020304)
self.assertEqual(self.rf.read('R2'), 0x04030201)
@itest_setregs("R1=0x01020304","R2=0x05060708", "R3=0","R4=0xF001")
@itest_multiple(["sxth r1, r2", "sxth r3, r4", "sxth r5, r4, ROR #8"])
def test_sxth(self):
self.assertEqual(self.rf.read('R1'), 0x0708)
self.assertEqual(self.rf.read('R3'), 0xFFFFF001)
self.assertEqual(self.rf.read('R5'), 0xF0)
@itest_custom("blx r1")
def test_blx_reg_sym(self):
dest = BitVecVariable(32, 'dest')
self.cpu.memory.constraints.add(dest >= 0x1000)
self.cpu.memory.constraints.add(dest <= 0x1001)
self.cpu.R1 = dest
# First, make sure we raise when the mode is symbolic and ambiguous
with self.assertRaises(Concretize) as cm:
self.cpu.execute()
# Then, make sure we have the correct expression
e = cm.exception
all_modes = solver.get_all_values(self.cpu.memory.constraints, e.expression)
self.assertIn(CS_MODE_THUMB, all_modes)
self.assertIn(CS_MODE_ARM, all_modes)
# Assuming we're in ARM mode, ensure the callback toggles correctly.
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
# The setstate callback expects a State as its first argument; since we
# don't have a state, the unit test itself is an okay approximation, since
# the cpu lives in self.cpu
e.setstate(self, CS_MODE_THUMB)
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
@itest_setregs("R1=0x00000008") # pc/r15 is set to 0x1004 in _setupCpu()
@itest("add pc, pc, r1")
def test_add_to_pc(self):
self.assertEqual(self.rf.read('R15'), 0x1014)
# Make sure a cpu will survive a round trip through pickling/unpickling
def test_arm_save_restore_cpu(self):
import pickle
dumped_s = pickle.dumps(self.cpu)
self.cpu = pickle.loads(dumped_s)