-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revamp Python regression tests suite (#2022)
* Fix Python regression test suite (partial) * Fix Python regression test suite * Add a test for mapping at high addresses * Add ctl tests
- Loading branch information
Showing
58 changed files
with
1,944 additions
and
1,496 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
|
@@ -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) | ||
|
||
|
@@ -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() |
Oops, something went wrong.