|
1 |
| -from __future__ import print_function |
| 1 | + |
| 2 | +import regress |
| 3 | + |
2 | 4 | from unicorn import *
|
3 | 5 | from unicorn.arm_const import *
|
4 |
| -import regress |
5 | 6 |
|
6 |
| -# code to be emulated |
7 |
| -''' |
8 |
| -ins = { |
9 |
| - 0x00008cd4: """ |
10 |
| - push {r11} |
11 |
| - add r11, sp, #0 |
12 |
| - mov r3, pc |
13 |
| - mov r0, r3 |
14 |
| - sub sp, r11, #0 |
15 |
| - pop {r11} |
16 |
| - bx lr |
17 |
| - """, |
18 |
| - 0x00008cf0: """ |
19 |
| - push {r11} |
20 |
| - add r11, sp, #0 |
21 |
| - push {r6} |
22 |
| - add r6, pc, $1 |
23 |
| - bx r6 |
24 |
| - .code 16 |
25 |
| - mov r3, pc |
26 |
| - add r3, $0x4 |
27 |
| - push {r3} |
28 |
| - pop {pc} |
29 |
| - .code 32 |
30 |
| - pop {r6} |
31 |
| - mov r0, r3 |
32 |
| - sub sp, r11, #0 |
33 |
| - pop {r11} |
34 |
| - bx lr |
35 |
| - """, |
36 |
| - 0x00008d20: """ |
37 |
| - push {r11} |
38 |
| - add r11, sp, #0 |
39 |
| - mov r3, lr |
40 |
| - mov r0, r3 |
41 |
| - sub sp, r11, #0 |
42 |
| - pop {r11} |
43 |
| - bx lr |
44 |
| - """, |
45 |
| - 0x00008d68: "bl 0x8cd4\n" |
46 |
| - "mov r4, r0\n" |
47 |
| - "bl 0x8cf0\n" |
48 |
| - "mov r3, r0\n" |
49 |
| - "add r4, r4, r3\n" |
50 |
| - "bl 0x8d20\n" |
51 |
| - "mov r3, r0\n" |
52 |
| - "add r2, r4, r3", |
53 |
| -} |
54 |
| -''' |
| 7 | + |
| 8 | +MAIN_ADDRESS = 0x8d68 |
| 9 | +ADDRESS = MAIN_ADDRESS & ~(0x1000 - 1) |
| 10 | +STACK_ADDR = ADDRESS + 0x1000 |
| 11 | + |
55 | 12 |
|
56 | 13 | class BxTwiceTest(regress.RegressTest):
|
57 | 14 | def runTest(self):
|
58 |
| - ADDRESS = 0x8000 |
59 |
| - MAIN_ADDRESS = 0x8d68 |
60 |
| - STACK_ADDR = ADDRESS + 0x1000 |
61 |
| - |
| 15 | + # code to be emulated |
62 | 16 | code = {
|
63 |
| - 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', |
64 |
| - 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', |
65 |
| - 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', |
66 |
| - 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' |
| 17 | + 0x8cd4: ( |
| 18 | + b'\x04\xb0\x2d\xe5' # 8cd4 push {r11} |
| 19 | + b'\x00\xb0\x8d\xe2' # 8cd8 add r11, sp, #0 |
| 20 | + b'\x0f\x30\xa0\xe1' # 8cdc mov r3, pc |
| 21 | + b'\x03\x00\xa0\xe1' # 8ce0 mov r0, r3 |
| 22 | + b'\x00\xd0\x4b\xe2' # 8ce4 sub sp, r11, #0 |
| 23 | + b'\x04\xb0\x9d\xe4' # 8ce8 pop {r11} |
| 24 | + b'\x1e\xff\x2f\xe1' # 8cec bx lr |
| 25 | + ), |
| 26 | + 0x8cf0: ( |
| 27 | + b'\x04\xb0\x2d\xe5' # 8cf0 push {r11} |
| 28 | + b'\x00\xb0\x8d\xe2' # 8cf4 add r11, sp, #0 |
| 29 | + b'\x04\x60\x2d\xe5' # 8cf8 push {r6} |
| 30 | + b'\x01\x60\x8f\xe2' # 8cfc add r6, pc, $1 |
| 31 | + b'\x16\xff\x2f\xe1' # 8d00 bx r6 |
| 32 | + # .thumb |
| 33 | + b'\x7b\x46' # 8d04 mov r3, pc |
| 34 | + b'\x03\xf1\x08\x03' # 8d06 add r3, $0x8 # elicn: used to be $0x4 but it kept failing |
| 35 | + b'\x08\xb4' # 8d0a push {r3} |
| 36 | + b'\x00\xbd' # 8d0c pop {pc} |
| 37 | + b'\x00\x00' # 8d0e (alignment) |
| 38 | + # .arm |
| 39 | + b'\x04\x60\x9d\xe4' # 8d10 pop {r6} |
| 40 | + b'\x03\x00\xa0\xe1' # 8d14 mov r0, r3 |
| 41 | + b'\x00\xd0\x4b\xe2' # 8d18 sub sp, r11, #0 |
| 42 | + b'\x04\xb0\x9d\xe4' # 8d1c pop {r11} |
| 43 | + b'\x1e\xff\x2f\xe1' # 8d20 bx lr |
| 44 | + ), |
| 45 | + 0x8d24: ( # elicn: used to be 0x8d20 but it caused this block to overlap with the previous one |
| 46 | + b'\x04\xb0\x2d\xe5' # 8d24 push {r11} |
| 47 | + b'\x00\xb0\x8d\xe2' # 8d28 add r11, sp, #0 |
| 48 | + b'\x0e\x30\xa0\xe1' # 8d2c mov r3, lr |
| 49 | + b'\x03\x00\xa0\xe1' # 8d20 mov r0, r3 |
| 50 | + b'\x00\xd0\x4b\xe2' # 8d34 sub sp, r11, #0 |
| 51 | + b'\x04\xb0\x9d\xe4' # 8d38 pop {r11} |
| 52 | + b'\x1e\xff\x2f\xe1' # 8d3c bx lr |
| 53 | + ), |
| 54 | + 0x8d68: ( |
| 55 | + b'\xd9\xff\xff\xeb' # 8d68 bl 0x8cd4 <-- MAIN_ADDRESS |
| 56 | + b'\x00\x40\xa0\xe1' # 8d6c mov r4, r0 |
| 57 | + b'\xde\xff\xff\xeb' # 8d70 bl 0x8cf0 |
| 58 | + b'\x00\x30\xa0\xe1' # 8d74 mov r3, r0 |
| 59 | + b'\x03\x40\x84\xe0' # 8d78 add r4, r4, r3 |
| 60 | + b'\xe8\xff\xff\xeb' # 8d7c bl 0x8d24 |
| 61 | + b'\x00\x30\xa0\xe1' # 8d80 mov r3, r0 |
| 62 | + b'\x03\x20\x84\xe0' # 8d84 add r2, r4, r3 |
| 63 | + ) |
67 | 64 | }
|
68 | 65 |
|
69 |
| - try: |
70 |
| - mu = Uc(UC_ARCH_ARM, UC_MODE_ARM) |
71 |
| - # map 2MB memory for this emulation |
72 |
| - mu.mem_map(ADDRESS, 2 * 1024 * 1024) |
| 66 | + mu = Uc(UC_ARCH_ARM, UC_MODE_ARM) |
| 67 | + |
| 68 | + mu.mem_map(ADDRESS, 0x1000) |
| 69 | + |
| 70 | + # write machine code to be emulated to memory |
| 71 | + for addr, c in code.items(): |
| 72 | + regress.logger.debug("Writing %d bytes to %#x", len(c), addr) |
| 73 | + mu.mem_write(addr, c) |
| 74 | + |
| 75 | + # initialize machine registers |
| 76 | + mu.reg_write(UC_ARM_REG_PC, MAIN_ADDRESS) |
| 77 | + mu.reg_write(UC_ARM_REG_SP, STACK_ADDR) |
| 78 | + |
| 79 | + regress.logger.debug("Starting emulation") |
| 80 | + |
| 81 | + # trace code only if we are debugging it |
| 82 | + if regress.logger.isEnabledFor(regress.logging.DEBUG): |
| 83 | + def __hook_code(uc, addr, size, _): |
| 84 | + cpsr, r0, r3, r4, r6 = uc.reg_read_batch(( |
| 85 | + UC_ARM_REG_CPSR, |
| 86 | + UC_ARM_REG_R0, |
| 87 | + UC_ARM_REG_R3, |
| 88 | + UC_ARM_REG_R4, |
| 89 | + UC_ARM_REG_R6 |
| 90 | + )) |
| 91 | + |
| 92 | + is_thumb = (cpsr >> 5) & 0b1 |
| 93 | + |
| 94 | + opcode = uc.mem_read(addr, size).hex() |
73 | 95 |
|
74 |
| - # write machine code to be emulated to memory |
75 |
| - for addr, c in code.items(): |
76 |
| - print("Writing chunk to 0x{:x}".format(addr)) |
77 |
| - mu.mem_write(addr, c) |
| 96 | + regress.logger.debug( |
| 97 | + "%-2s PC = %#06x | opcode = %-8s [R0 = %#06x, R3 = %#06x, R4 = %#07x, R6 = %#06x]", |
| 98 | + "T" if is_thumb else "", addr, opcode, r0, r3, r4, r6 |
| 99 | + ) |
78 | 100 |
|
79 |
| - # initialize machine registers |
80 |
| - mu.reg_write(UC_ARM_REG_SP, STACK_ADDR) |
| 101 | + mu.hook_add(UC_HOOK_CODE, __hook_code) |
81 | 102 |
|
82 |
| - print("Starting emulation") |
| 103 | + mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS])) |
83 | 104 |
|
84 |
| - # emulate code in infinite time & unlimited instructions |
85 |
| - mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS])) |
| 105 | + regress.logger.debug("Emulation done") |
86 | 106 |
|
87 |
| - print("Emulation done") |
| 107 | + self.assertEqual(0x8ce4 + 0x8d10 + 0x8d80, mu.reg_read(UC_ARM_REG_R2)) |
88 | 108 |
|
89 |
| - r2 = mu.reg_read(UC_ARM_REG_R2) |
90 |
| - print(">>> r2: 0x{:08x}".format(r2)) |
91 | 109 |
|
92 |
| - except UcError as e: |
93 |
| - self.fail("ERROR: %s" % e) |
| 110 | +if __name__ == '__main__': |
| 111 | + regress.main() |
0 commit comments