summaryrefslogtreecommitdiff
path: root/arch/armv7/test.py
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2024-03-05 19:50:13 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2024-03-05 20:34:34 -0500
commite093c21ed880ac3eb72119be15093ee04f8ce299 (patch)
tree9f720ebdc0ae415734b1199ed341668c69710a94 /arch/armv7/test.py
parent0609276712622908254065546102381466033141 (diff)
Move architecture modules into the API repo
Diffstat (limited to 'arch/armv7/test.py')
-rwxr-xr-xarch/armv7/test.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/arch/armv7/test.py b/arch/armv7/test.py
new file mode 100755
index 00000000..9ffb040e
--- /dev/null
+++ b/arch/armv7/test.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+
+test_cases_arm = [
+ # s14 = load(0x1000 + 8 + 912)
+ (b'\xe4\x7a\x9f\xed', 'LLIL_SET_REG(s14,LLIL_LOAD(LLIL_ADD(LLIL_CONST_PTR(4104),LLIL_CONST(912))))'), # vldr s14, [pc, #0x390]
+ (b'\x00\x7a\xcd\xed', 'LLIL_STORE(LLIL_REG(sp),LLIL_REG(s15))'), # vstr s15, [sp]
+ (b'\x90\x2a\x17\xee', 'LLIL_SET_REG(r2,LLIL_REG(s15))'), # vmov r2, s15
+ # encoding A1 of BFI
+ # r0 = (r1 & 0b11111111111111111111111111100011) | ((r1 & 0b111) << 2)
+ (b'\x11\x01\xc4\xe7', 'LLIL_SET_REG(r0,LLIL_OR(LLIL_AND(LLIL_REG(r0),LLIL_CONST(4294967267)),LLIL_LSL(LLIL_AND(LLIL_REG(r1),LLIL_CONST(7)),LLIL_CONST(2))))'), # bfi r0, r1, #2, #3
+ # temp0 = r2*r3; r0=tmp0&0xFFFFFFFF; r1=tmp0>>32 ... LOGICAL shift since mul is unsigned
+ (b'\x92\x03\x81\xe0', 'LLIL_SET_REG(temp0,LLIL_MUL(LLIL_REG(r2),LLIL_REG(r3))); LLIL_SET_REG(r0,LLIL_LOW_PART(LLIL_REG(temp0))); LLIL_SET_REG(r1,LLIL_LSR(LLIL_REG(temp0),LLIL_CONST(32)))'), # umull r0, r1, r2, r3
+ # same, but ARITHMETIC shift since mul is signed
+ (b'\x92\x03\xc1\xe0', 'LLIL_SET_REG(temp0,LLIL_MUL(LLIL_REG(r2),LLIL_REG(r3))); LLIL_SET_REG(r0,LLIL_LOW_PART(LLIL_REG(temp0))); LLIL_SET_REG(r1,LLIL_ASR(LLIL_REG(temp0),LLIL_CONST(32)))'), # smull r0, r1, r2, r3
+ # multiply and accumulate: mla r0, r1, r2, r3 lift to r0 = r3 + (r1 * r2)
+ (b'\x91\x32\x20\xe0', 'LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r3),LLIL_MUL(LLIL_REG(r1),LLIL_REG(r2))))'), # mla r0, r1, r2, r3
+ # multiply and subtract: mls r0, r1, r2, r3 lift to r0 = r3 - (r1 * r2)
+ (b'\x91\x32\x60\xe0', 'LLIL_SET_REG(r0,LLIL_SUB(LLIL_REG(r3),LLIL_MUL(LLIL_REG(r1),LLIL_REG(r2))))'), # mls r0, r1, r2, r3
+ # sdiv r1, r2, r3 lift to r1=r2/r3 (signed)
+ (b'\x12\xf3\x11\xe7', 'LLIL_SET_REG(r1,LLIL_DIVS(LLIL_REG(r2),LLIL_REG(r3)))'), # 'sdiv r1, r2, r3'
+ # udiv r1, r2, r3 lift to r1=r2/r3 (unsigned)
+ (b'\x12\xf3\x31\xe7', 'LLIL_SET_REG(r1,LLIL_DIVU(LLIL_REG(r2),LLIL_REG(r3)))'), # 'udiv r1, r2, r3'
+ # ubfx <dst> <src> <lsb> <width>
+ # ubfx r1, r2, #4, #4 should extract b7..b4, lift to r1=(r2>>4)&0b1111
+ (b'\x52\x12\xe3\xe7', 'LLIL_SET_REG(r1,LLIL_AND(LLIL_LSR(LLIL_REG(r2),LLIL_CONST(4)),LLIL_CONST(15)))'), # 'ubfx r1, r2, #4, #4'
+ # ubfx r2, r3, #4, #5 should extract b8..b4, lift to r2=(r3>>4)&0b11111
+ (b'\x53\x22\xe4\xe7', 'LLIL_SET_REG(r2,LLIL_AND(LLIL_LSR(LLIL_REG(r3),LLIL_CONST(4)),LLIL_CONST(31)))'), # 'ubfx r2, r3, #4, #5'
+ # ubfx r3, r4, #0, #16 should extract b15..b0, lift to r3=(r4>>0)&0b1111111111111111
+ # though no shift is needed, no reason to complicate the lifter as the core should see x>>0 == x
+ (b'\x54\x30\xef\xe7', 'LLIL_SET_REG(r3,LLIL_AND(LLIL_LSR(LLIL_REG(r4),LLIL_CONST(0)),LLIL_CONST(65535)))'), # 'ubfx r3, r4, #0, #16'
+ (b'\x00\xf0\x20\xe3', ''), # nop, gets optimized from function
+]
+
+test_cases_thumb2 = [
+ # itttt eq; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0;
+ # generate 1 if/goto that encloses 4
+ (b'\x01\xbf\x00\x44\x00\x44\x00\x44\x00\x44', 'LLIL_IF(LLIL_FLAG(z),1,6); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_GOTO(6)'),
+ # ittt eq; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0;
+ # generate 1 if/goto that encloses 3
+ (b'\x02\xbf\x00\x44\x00\x44\x00\x44\x00\x44', 'LLIL_IF(LLIL_FLAG(z),1,5); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_GOTO(5); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0)))'),
+ # itt eq; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0;
+ # generate 1 if/goto that encloses 2
+ (b'\x04\xbf\x00\x44\x00\x44\x00\x44\x00\x44', 'LLIL_IF(LLIL_FLAG(z),1,4); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_GOTO(4); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0)))'),
+ # it eq; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0; add r0, r0, r0;
+ # generate 1 if/goto that encloses 1
+ (b'\x08\xbf\x00\x44\x00\x44\x00\x44\x00\x44', 'LLIL_IF(LLIL_FLAG(z),1,3); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_GOTO(3); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0))); LLIL_SET_REG(r0,LLIL_ADD(LLIL_REG(r0),LLIL_REG(r0)))'),
+ # unsigned extend and add byte - LLIL_LOW_PART() has hidden parameter size=1
+ (b'\x52\xfa\x83\xf1', 'LLIL_SET_REG(r1,LLIL_ADD(LLIL_REG(r2),LLIL_ZX(LLIL_LOW_PART(LLIL_REG(r3)))))'), # uxtab r1, r2, r3
+ # unsigned extend and add halfword - LLIL_LOW_PART() has hidden parameter size=2
+ (b'\x12\xfa\x83\xf1', 'LLIL_SET_REG(r1,LLIL_ADD(LLIL_REG(r2),LLIL_ZX(LLIL_LOW_PART(LLIL_REG(r3)))))'), # ustah r1, r2, r3
+ # clear b4...b2 so lift to r1 = r1 & 0b11111111111111111111111111100011
+ (b'\x6f\xf3\x84\x01', 'LLIL_SET_REG(r1,LLIL_AND(LLIL_REG(r1),LLIL_CONST(4294967267)))'), # bfc r1, #2, #3
+ # these differ only when the ifThenBlock varies
+ # TODO: vary the ifThenBlock state
+ (b'\x62\xeb\x03\x01', 'LLIL_SET_REG(r1,LLIL_SBB(LLIL_REG(r2),LLIL_REG(r3),LLIL_NOT(LLIL_FLAG(c))))'), # sbc r1, r2, r3
+ (b'\x72\xeb\x03\x01', 'LLIL_SET_REG(r1,LLIL_SBB(LLIL_REG(r2),LLIL_REG(r3),LLIL_NOT(LLIL_FLAG(c))))'), # sbcs r1, r2, r3
+ # same as arm
+ (b'\x92\xfb\xf3\xf1', 'LLIL_SET_REG(r1,LLIL_DIVS(LLIL_REG(r2),LLIL_REG(r3)))'), # sdiv r1, r2, r3
+ # same as arm
+ (b'\xb2\xfb\xf3\xf1', 'LLIL_SET_REG(r1,LLIL_DIVU(LLIL_REG(r2),LLIL_REG(r3)))'), # udiv r1, r2, r3
+ # encoding T1 of BFI should lift the same as encoding A1
+ (b'\x61\xf3\x84\x00', 'LLIL_SET_REG(r0,LLIL_OR(LLIL_AND(LLIL_REG(r0),LLIL_CONST(4294967267)),LLIL_LSL(LLIL_AND(LLIL_REG(r1),LLIL_CONST(7)),LLIL_CONST(2))))'), # bfi r0, r1, #2, #3
+ (b'\xb1\xfa\x81\xf0', 'LLIL_SET_REG(temp0,LLIL_CONST(0)); LLIL_SET_REG(temp1,LLIL_REG(r1)); LLIL_GOTO(3); LLIL_IF(LLIL_CMP_NE(LLIL_REG(temp1),LLIL_CONST(0)),4,7); LLIL_SET_REG(temp1,LLIL_LSR(LLIL_REG(temp1),LLIL_CONST(1))); LLIL_SET_REG(temp0,LLIL_ADD(LLIL_REG(temp0),LLIL_CONST(1))); LLIL_GOTO(3); LLIL_SET_REG(r0,LLIL_SUB(LLIL_CONST(32),LLIL_REG(temp0)))'), # 'clz r0, r1'
+ (b'\x00\xbf', ''), # nop, gets optmized from function
+]
+
+import sys
+import binaryninja
+from binaryninja import core
+from binaryninja import binaryview
+from binaryninja import lowlevelil
+
+def il2str(il):
+ if isinstance(il, lowlevelil.LowLevelILInstruction):
+ return '%s(%s)' % (il.operation.name, ','.join([il2str(o) for o in il.operands]))
+ else:
+ return str(il)
+
+# TODO: make this less hacky
+def instr_to_il(data, plat_name):
+ platform = binaryninja.Platform[plat_name]
+ # make a pretend function that returns
+
+ sled = b''
+ sled_len = 0x1000
+ if plat_name == 'linux-thumb2':
+ sled = b'\x00\xbf' * (sled_len//2)
+ elif plat_name == 'linux-armv7':
+ sled = b'\x00\xf0\x20\xe3' * (sled_len//4)
+
+ bv = binaryview.BinaryView.new(sled + data)
+ bv.add_function(sled_len, plat=platform)
+ assert len(bv.functions) == 1
+
+ result = []
+ for block in bv.functions[0].low_level_il:
+ for il in block:
+ result.append(il2str(il))
+ result = '; '.join(result)
+ assert result.endswith('LLIL_UNDEF()')
+ result = result[0:result.index('LLIL_UNDEF()')]
+ if result.endswith('; '):
+ result = result[0:-2]
+
+ return result
+
+def check(test_i, data, actual, expected):
+ print_always = False
+
+ if (actual != expected) or print_always:
+ print('\t test: %d' % test_i)
+ print('\t input: %s' % data.hex())
+ print('\texpected: %s' % expected)
+ print('\t actual: %s' % actual)
+
+ if actual != expected:
+ print('MISMATCH!')
+ sys.exit(-1)
+
+if __name__ == '__main__':
+ for (test_i, (data, expected)) in enumerate(test_cases_arm):
+ actual = instr_to_il(data, 'linux-armv7')
+ check(test_i, data, actual, expected)
+
+ for (test_i, (data, expected)) in enumerate(test_cases_thumb2):
+ actual = instr_to_il(data, 'linux-thumb2')
+ check(test_i, data, actual, expected)
+
+ print('success!')
+ sys.exit(0)