Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp Python regression tests suite #2022

Merged
merged 4 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 95 additions & 77 deletions tests/regress/arm_bx_unmapped.py
Original file line number Diff line number Diff line change
@@ -1,93 +1,111 @@
from __future__ import print_function

import regress

from unicorn import *
from unicorn.arm_const import *
import regress

# code to be emulated
'''
ins = {
0x00008cd4: """
push {r11}
add r11, sp, #0
mov r3, pc
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008cf0: """
push {r11}
add r11, sp, #0
push {r6}
add r6, pc, $1
bx r6
.code 16
mov r3, pc
add r3, $0x4
push {r3}
pop {pc}
.code 32
pop {r6}
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008d20: """
push {r11}
add r11, sp, #0
mov r3, lr
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008d68: "bl 0x8cd4\n"
"mov r4, r0\n"
"bl 0x8cf0\n"
"mov r3, r0\n"
"add r4, r4, r3\n"
"bl 0x8d20\n"
"mov r3, r0\n"
"add r2, r4, r3",
}
'''

MAIN_ADDRESS = 0x8d68
ADDRESS = MAIN_ADDRESS & ~(0x1000 - 1)
STACK_ADDR = ADDRESS + 0x1000


class BxTwiceTest(regress.RegressTest):
def runTest(self):
ADDRESS = 0x8000
MAIN_ADDRESS = 0x8d68
STACK_ADDR = ADDRESS + 0x1000

# code to be emulated
code = {
0x8cf0: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x04`-\xe5\x01`\x8f\xe2\x16\xff/\xe1{F\x03\xf1\x04\x03\x08\xb4\x00\xbd\x00\x00\x04`\x9d\xe4\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8d20: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x0e0\xa0\xe1\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8cd4: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x0f0\xa0\xe1\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8d68: '\xd9\xff\xff\xeb\x00@\xa0\xe1\xde\xff\xff\xeb\x000\xa0\xe1\x03@\x84\xe0\xe7\xff\xff\xeb\x000\xa0\xe1\x03 \x84\xe0'
0x8cd4: (
b'\x04\xb0\x2d\xe5' # 8cd4 push {r11}
b'\x00\xb0\x8d\xe2' # 8cd8 add r11, sp, #0
b'\x0f\x30\xa0\xe1' # 8cdc mov r3, pc
b'\x03\x00\xa0\xe1' # 8ce0 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8ce4 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8ce8 pop {r11}
b'\x1e\xff\x2f\xe1' # 8cec bx lr
),
0x8cf0: (
b'\x04\xb0\x2d\xe5' # 8cf0 push {r11}
b'\x00\xb0\x8d\xe2' # 8cf4 add r11, sp, #0
b'\x04\x60\x2d\xe5' # 8cf8 push {r6}
b'\x01\x60\x8f\xe2' # 8cfc add r6, pc, $1
b'\x16\xff\x2f\xe1' # 8d00 bx r6
# .thumb
b'\x7b\x46' # 8d04 mov r3, pc
b'\x03\xf1\x08\x03' # 8d06 add r3, $0x8 # elicn: used to be $0x4 but it kept failing
b'\x08\xb4' # 8d0a push {r3}
b'\x00\xbd' # 8d0c pop {pc}
b'\x00\x00' # 8d0e (alignment)
# .arm
b'\x04\x60\x9d\xe4' # 8d10 pop {r6}
b'\x03\x00\xa0\xe1' # 8d14 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8d18 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8d1c pop {r11}
b'\x1e\xff\x2f\xe1' # 8d20 bx lr
),
0x8d24: ( # elicn: used to be 0x8d20 but it caused this block to overlap with the previous one
b'\x04\xb0\x2d\xe5' # 8d24 push {r11}
b'\x00\xb0\x8d\xe2' # 8d28 add r11, sp, #0
b'\x0e\x30\xa0\xe1' # 8d2c mov r3, lr
b'\x03\x00\xa0\xe1' # 8d20 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8d34 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8d38 pop {r11}
b'\x1e\xff\x2f\xe1' # 8d3c bx lr
),
0x8d68: (
b'\xd9\xff\xff\xeb' # 8d68 bl 0x8cd4 <-- MAIN_ADDRESS
b'\x00\x40\xa0\xe1' # 8d6c mov r4, r0
b'\xde\xff\xff\xeb' # 8d70 bl 0x8cf0
b'\x00\x30\xa0\xe1' # 8d74 mov r3, r0
b'\x03\x40\x84\xe0' # 8d78 add r4, r4, r3
b'\xe8\xff\xff\xeb' # 8d7c bl 0x8d24
b'\x00\x30\xa0\xe1' # 8d80 mov r3, r0
b'\x03\x20\x84\xe0' # 8d84 add r2, r4, r3
)
}

try:
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

mu.mem_map(ADDRESS, 0x1000)

# write machine code to be emulated to memory
for addr, c in code.items():
regress.logger.debug("Writing %d bytes to %#x", len(c), addr)
mu.mem_write(addr, c)

# initialize machine registers
mu.reg_write(UC_ARM_REG_PC, MAIN_ADDRESS)
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR)

regress.logger.debug("Starting emulation")

# trace code only if we are debugging it
if regress.logger.isEnabledFor(regress.logging.DEBUG):
def __hook_code(uc, addr, size, _):
cpsr, r0, r3, r4, r6 = uc.reg_read_batch((
UC_ARM_REG_CPSR,
UC_ARM_REG_R0,
UC_ARM_REG_R3,
UC_ARM_REG_R4,
UC_ARM_REG_R6
))

is_thumb = (cpsr >> 5) & 0b1

opcode = uc.mem_read(addr, size).hex()

# write machine code to be emulated to memory
for addr, c in code.items():
print("Writing chunk to 0x{:x}".format(addr))
mu.mem_write(addr, c)
regress.logger.debug(
"%-2s PC = %#06x | opcode = %-8s [R0 = %#06x, R3 = %#06x, R4 = %#07x, R6 = %#06x]",
"T" if is_thumb else "", addr, opcode, r0, r3, r4, r6
)

# initialize machine registers
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR)
mu.hook_add(UC_HOOK_CODE, __hook_code)

print("Starting emulation")
mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS]))

# emulate code in infinite time & unlimited instructions
mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS]))
regress.logger.debug("Emulation done")

print("Emulation done")
self.assertEqual(0x8ce4 + 0x8d10 + 0x8d80, mu.reg_read(UC_ARM_REG_R2))

r2 = mu.reg_read(UC_ARM_REG_R2)
print(">>> r2: 0x{:08x}".format(r2))

except UcError as e:
self.fail("ERROR: %s" % e)
if __name__ == '__main__':
regress.main()
12 changes: 7 additions & 5 deletions tests/regress/arm_bxeq_hang.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
#!/usr/bin/python

import regress

from unicorn import *
from unicorn.arm_const import *

import regress

class BxHang(regress.RegressTest):

def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex')) # bxeq lr; mov r0, r0
uc.mem_write(0x1000, b'\x1e\xff\x2f\x01\x00\x00\xa0\xe1') # bxeq lr; mov r0, r0
uc.count = 0

def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
regress.logger.debug('enter block %#06x', addr)
uc.count += 1

uc.reg_write(UC_ARM_REG_LR, 0x1004)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
print 'block should only run once'

regress.logger.debug('block should only run once')
uc.emu_start(0x1000, 0x1004)

self.assertEqual(uc.count, 1)


if __name__ == '__main__':
regress.main()
49 changes: 23 additions & 26 deletions tests/regress/arm_fp_vfp_disabled.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
#!/usr/bin/python
# coding=utf8

# Added by Peter Mackay, relating to issue 571
# "ARM NEON/VFP support seems to exist but is disabled by default"
# https://github.com/unicorn-engine/unicorn/issues/571

import regress

from unicorn import *
from unicorn.arm_const import *

import regress

CODE = (
b'\x11\xEE\x50\x1F' # MRC p15, #0, r1, c1, c0, #2
b'\x41\xF4\x70\x01' # ORR r1, r1, #(0xf << 20)
b'\x01\xEE\x50\x1F' # MCR p15, #0, r1, c1, c0, #2
b'\x4F\xF0\x00\x01' # MOV r1, #0
b'\x07\xEE\x95\x1F' # MCR p15, #0, r1, c7, c5, #4
b'\x4F\xF0\x80\x40' # MOV r0,#0x40000000
b'\xE8\xEE\x10\x0A' # FMXR FPEXC, r0
b'\x2d\xed\x02\x8b' # vpush {d8}
)

BASE = 0x1000

class FpVfpDisabled(regress.RegressTest):

def runTest(self):
# MRC p15, #0, r1, c1, c0, #2
# ORR r1, r1, #(0xf << 20)
# MCR p15, #0, r1, c1, c0, #2
# MOV r1, #0
# MCR p15, #0, r1, c7, c5, #4
# MOV r0,#0x40000000
# FMXR FPEXC, r0
code = '11EE501F'
code += '41F47001'
code += '01EE501F'
code += '4FF00001'
code += '07EE951F'
code += '4FF08040'
code += 'E8EE100A'
# vpush {d8}
code += '2ded028b'

address = 0x1000
mem_size = 0x1000
code_bytes = code.decode('hex')


uc = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
uc.mem_map(address, mem_size)
uc.mem_write(address, code_bytes)
uc.reg_write(UC_ARM_REG_SP, address + mem_size)
uc.emu_start(address + 1, address + len(code_bytes))

uc.mem_map(BASE, mem_size)
uc.mem_write(BASE, CODE)
uc.reg_write(UC_ARM_REG_SP, BASE + mem_size - 4)

uc.emu_start(BASE + 1, BASE + len(CODE))


if __name__ == '__main__':
regress.main()
56 changes: 26 additions & 30 deletions tests/regress/arm_init_input_crash.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,44 @@
# Python sample ported by Loi Anh Tuan <[email protected]>
#

import regress

from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *


# code to be emulated
ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
THUMB_CODE = "\x83\xb0" # sub sp, #0xc
ARM_CODE = (
b"\x37\x00\xa0\xe3" # mov r0, #0x37
b"\x03\x10\x42\xe0" # sub r1, r2, r3
)

THUMB_CODE = b"\x83\xb0" # sub sp, #0xc

# memory address where emulation starts
ADDRESS = 0xF0000000
ADDRESS = 0xF0000000


# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
regress.logger.debug(">>> Tracing basic block at %#x, block size = %#x", address, size)


# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
regress.logger.debug(">>> Tracing instruction at %#x, instruction size = %u", address, size)


# Test ARM
def test_arm():
print("Emulate ARM code")
try:
class TestInitInputCrash(regress.RegressTest):
def test_arm(self):
regress.logger.debug("Emulate ARM code")

# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

mem_size = 2 * (1024 * 1024)
mu.mem_map(ADDRESS, mem_size)

stack_address = ADDRESS + mem_size
stack_size = stack_address # >>> here huge memory size
mu.mem_map(stack_address, stack_size)
Expand All @@ -58,20 +63,16 @@ def test_arm():
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))

# now print out some registers
print(">>> Emulation done. Below is the CPU context")
regress.logger.debug(">>> Emulation done. Below is the CPU context")

r0 = mu.reg_read(UC_ARM_REG_R0)
r1 = mu.reg_read(UC_ARM_REG_R1)
print(">>> R0 = 0x%x" %r0)
print(">>> R1 = 0x%x" %r1)

except UcError as e:
print("ERROR: %s" % e)
regress.logger.debug(">>> R0 = %#x", r0)
regress.logger.debug(">>> R1 = %#x", r1)

def test_thumb(self):
regress.logger.debug("Emulate THUMB code")

def test_thumb():
print("Emulate THUMB code")
try:
# Initialize emulator in thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)

Expand All @@ -91,19 +92,14 @@ def test_thumb():
mu.hook_add(UC_HOOK_CODE, hook_code)

# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(THUMB_CODE))
mu.emu_start(ADDRESS | 0b1, ADDRESS + len(THUMB_CODE))

# now print out some registers
print(">>> Emulation done. Below is the CPU context")
regress.logger.debug(">>> Emulation done. Below is the CPU context")

sp = mu.reg_read(UC_ARM_REG_SP)
print(">>> SP = 0x%x" %sp)

except UcError as e:
print("ERROR: %s" % e)
regress.logger.debug(">>> SP = %#x", sp)


if __name__ == '__main__':
test_arm()
print("=" * 20)
test_thumb()
regress.main()
Loading
Loading