- Switched to the ubuntu-24.04-arm runner - Bumped Windows runner to windows-2022 and Visual Studio 17 2022 GENERATORS - Minor changes about checks in workflow jobs - Fixed the pagefile job (even though should not be really needed) - Refreshed the TO BE CHECKED regress tests to either update or remove the skip conditions - Added a test to check if the created sdist archive is ok
180 lines
5.5 KiB
Python
180 lines
5.5 KiB
Python
import platform
|
|
import regress
|
|
import sys
|
|
import unittest
|
|
from unicorn import *
|
|
from unicorn.arm_const import *
|
|
from unicorn.x86_const import *
|
|
|
|
# count down from maxint to zero
|
|
_VALID_CODE = (
|
|
b'\x31\xc9' # xor ecx, ecx
|
|
b'\x49' # _top: dec ecx
|
|
b'\xf3\x90' # pause
|
|
b'\xe3\xfb' # jecxz _top
|
|
b'\xf4' # _end: hlt
|
|
)
|
|
|
|
_INVALID_CODE = (
|
|
b'\xff\xff' # (invalid)
|
|
)
|
|
|
|
CODE = _VALID_CODE + _INVALID_CODE
|
|
|
|
BASE = 0x100000
|
|
|
|
|
|
class TestCtl(regress.RegressTest):
|
|
|
|
def test_mode(self):
|
|
uc = Uc(UC_ARCH_ARM, UC_MODE_BIG_ENDIAN)
|
|
|
|
# changing cpu model to one that supports EB
|
|
uc.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_M0)
|
|
|
|
# changing cpu model to one that does not support EB; this is expected to fail
|
|
with self.assertRaises(UcError) as ex:
|
|
uc.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_A8)
|
|
|
|
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
|
|
|
|
# make sure we stay with the configuration we set beforehand
|
|
self.assertEqual(UC_ARCH_ARM, uc.ctl_get_arch())
|
|
self.assertEqual(UC_MODE_BIG_ENDIAN, uc.ctl_get_mode())
|
|
self.assertEqual(UC_CPU_ARM_CORTEX_M0, uc.ctl_get_cpu_model())
|
|
|
|
@unittest.skipIf(sys.version_info < (3, 7), reason="requires python3.7 or higher")
|
|
@unittest.skip('TO BE CHECKED!')
|
|
def test_page_size(self):
|
|
SIZE_4KB = 4 * 1024 ** 1
|
|
SIZE_2MB = 2 * 1024 ** 2
|
|
|
|
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
|
|
|
|
# set page size to 2 MiB; this should work
|
|
uc.ctl_set_page_size(SIZE_2MB)
|
|
|
|
# was it set properly?
|
|
self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
|
|
|
|
# set a page size which is not a power of 2
|
|
with self.assertRaises(UcError) as ex:
|
|
uc.ctl_set_page_size(SIZE_2MB + 0xbad)
|
|
|
|
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
|
|
|
|
# are we still with the valid value?
|
|
self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
|
|
|
|
# force uc to complete its initialization by triggering a random api
|
|
uc.ctl_flush_tb()
|
|
|
|
# set a page size after uc has completed its initialization
|
|
with self.assertRaises(UcError) as ex:
|
|
uc.ctl_set_page_size(SIZE_4KB)
|
|
|
|
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
|
|
|
|
# are we still with the valid value?
|
|
self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
|
|
|
|
def test_timeout(self):
|
|
MILLIS_1S = 1000
|
|
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
|
|
|
uc.mem_map(BASE, 0x1000)
|
|
uc.mem_write(BASE, CODE)
|
|
|
|
# start a long emulation bound by timeout
|
|
uc.emu_start(BASE, BASE + len(CODE), timeout=MILLIS_1S)
|
|
|
|
# was timeout set properly? uc returns timeout in nanoseconds
|
|
self.assertEqual(MILLIS_1S * 1000, uc.ctl_get_timeout())
|
|
|
|
# no way we made it all the way down to zero
|
|
self.assertNotEqual(0, uc.reg_read(UC_X86_REG_ECX))
|
|
|
|
def test_exits(self):
|
|
WRONG_EXIT = BASE + len(CODE)
|
|
GOOD_EXIT = BASE + len(_VALID_CODE)
|
|
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
|
|
|
uc.mem_map(BASE, 0x1000)
|
|
uc.mem_write(BASE, CODE)
|
|
|
|
def __hook_code(uc, *args):
|
|
ecx = uc.reg_read(UC_X86_REG_ECX)
|
|
|
|
# 16 down to the count
|
|
if ecx == 0xfffffff0:
|
|
# fast-forward the counter and let it run for another 16 iterations
|
|
uc.reg_write(UC_X86_REG_ECX, 0x10)
|
|
|
|
uc.hook_add(UC_HOOK_CODE, __hook_code)
|
|
|
|
# enable exits
|
|
uc.ctl_exits_enabled(True)
|
|
|
|
# fix the exit point so we don't reach invalid code
|
|
uc.ctl_set_exits([GOOD_EXIT])
|
|
|
|
# start emulation, setting a wrong stopping point that will get us to invalid code
|
|
# since we enabled exits, the stopping point should be ignored
|
|
uc.emu_start(BASE, WRONG_EXIT, count=1)
|
|
|
|
# only one exit point was set
|
|
self.assertEqual(1, uc.ctl_get_exits_cnt())
|
|
|
|
# only one exit point, and it is the wrong one
|
|
self.assertSequenceEqual([GOOD_EXIT], uc.ctl_get_exits(), int)
|
|
|
|
# resume execution; rely on code hook to fast-forward the emulation
|
|
# stopping point is ignored due to enabled exits
|
|
uc.emu_start(BASE, WRONG_EXIT)
|
|
|
|
# did we exit on the right place?
|
|
# not failing on an invalid instruction is another good indication for that
|
|
self.assertEqual(GOOD_EXIT, uc.reg_read(UC_X86_REG_EIP))
|
|
|
|
@unittest.skipIf(sys.version_info < (3, 7), reason="requires python3.7 or higher")
|
|
def test_tlb_mode(self):
|
|
MAPPING_LO = 0x0000000001000000
|
|
MAPPING_HI = 0x0010000000000000
|
|
NOPSLED = b'\x90' * 8
|
|
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
|
|
|
uc.mem_map(MAPPING_LO, 0x1000)
|
|
uc.mem_write(MAPPING_LO, NOPSLED)
|
|
|
|
uc.emu_start(MAPPING_LO, MAPPING_LO + len(NOPSLED))
|
|
|
|
# # we should be fine here
|
|
# uc.emu_start(BASE, BASE + len(_VALID_CODE), count=1)
|
|
|
|
uc.mem_map(MAPPING_HI, 0x1000)
|
|
uc.mem_write(MAPPING_HI, NOPSLED)
|
|
|
|
# this should prevent us from mapping to high addresses
|
|
uc.ctl_set_tlb_mode(UC_TLB_CPU)
|
|
|
|
# this should fail
|
|
with self.assertRaises(UcError) as ex:
|
|
uc.emu_start(MAPPING_HI, MAPPING_HI + len(NOPSLED))
|
|
|
|
self.assertEqual(UC_ERR_FETCH_UNMAPPED, ex.exception.errno)
|
|
|
|
# ------------------------------------------------------
|
|
|
|
# this should allow us mapping to high addresses
|
|
uc.ctl_set_tlb_mode(UC_TLB_VIRTUAL)
|
|
|
|
# this should ok now
|
|
uc.emu_start(MAPPING_HI, MAPPING_HI + len(NOPSLED))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
regress.main()
|