def setUp(self):

        self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM)
        self._smt_solver = SmtSolver()
        self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size)

        self._ir_emulator = ReilEmulator(self._arch_info)

        self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper)
        self._smt_translator.set_arch_registers_size(self._arch_info.registers_size)

        self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info)

        self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info)
        self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info)
    def setUp(self):

        self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM)
        self._smt_solver = SmtSolver()
        self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size)

        self._ir_emulator = ReilEmulator(self._arch_info)

        self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper)
        self._smt_translator.set_arch_registers_size(self._arch_info.registers_size)

        self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info)

        self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info)
        self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info)
class ArmGadgetClassifierTests(unittest.TestCase):

    def setUp(self):

        self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM)
        self._smt_solver = SmtSolver()
        self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size)

        self._ir_emulator = ReilEmulator(self._arch_info)

        self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper)
        self._smt_translator.set_arch_registers_size(self._arch_info.registers_size)

        self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info)

        self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info)
        self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info)

    def _find_and_classify_gadgets(self, binary):
        g_finder = GadgetFinder(ArmDisassembler(architecture_mode=ARCH_ARM_MODE_ARM), bytearray(binary), ArmTranslator(), ARCH_ARM, ARCH_ARM_MODE_ARM)

        g_candidates = g_finder.find(0x00000000, len(binary), instrs_depth=4)
        g_classified = self._g_classifier.classify(g_candidates[0])

#         Debug:
#         self._print_candidates(g_candidates)
#         self._print_classified(g_classified)

        return g_candidates, g_classified

    def test_move_register_1(self):
        # testing : dst_reg <- src_reg
        binary  = b"\x04\x00\xa0\xe1"                     # 0x00 : (4)  mov    r0, r4
        binary += b"\x31\xff\x2f\xe1"                     # 0x04 : (4)  blx    r1

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.MoveRegister)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 1)
        self.assertTrue(ReilRegisterOperand("r14", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_move_register_2(self):
        # testing : dst_reg <- src_reg
        binary  = b"\x00\x00\x84\xe2"                     # 0x00 : (4)  add    r0, r4, #0
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.MoveRegister)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    # TODO: test_move_register_n: mul r0, r4, #1

    def test_load_constant_1(self):
        # testing : dst_reg <- constant
        binary  = b"\x0a\x20\xa0\xe3"                     # 0x00 : (4)  mov    r2, #10
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(10, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_2(self):
        # testing : dst_reg <- constant
        binary  = b"\x02\x20\x42\xe0"                     # 0x00 : (4)  sub    r2, r2, r2
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_3(self):
        # testing : dst_reg <- constant
        binary  = b"\x02\x20\x22\xe0"                     # 0x00 : (4)  eor    r2, r2, r2
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_4(self):
        # testing : dst_reg <- constant
        binary  = b"\x00\x20\x02\xe2"                     # 0x00 : (4)  and    r2, r2, #0
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_5(self):
        # testing : dst_reg <- constant
        binary  = b"\x00\x20\x02\xe2"                     # and    r2, r2, #0
        binary += b"\x21\x20\x82\xe3"                     # orr    r2, r2, #33
        binary += b"\x1e\xff\x2f\xe1"                     # bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(33, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_add_1(self):
        # testing : dst_reg <- src1_reg + src2_reg
        binary  = b"\x08\x00\x84\xe0"                     # 0x00 : (4)  add    r0, r4, r8
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.Arithmetic)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_sub_1(self):
        # testing : dst_reg <- src1_reg + src2_reg
        binary  = b"\x08\x00\x44\xe0"                     # 0x00 : (4)  sub    r0, r4, r8
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.Arithmetic)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "-")

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_memory_1(self):
        # testing : dst_reg <- m[src_reg]
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_memory_2(self):
        # testing : dst_reg <- m[src_reg + offset]
        binary  = b"\x33\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4 + 0x33]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    # TODO: ARM's ldr rd, [rn, r2] is not a valid classification right now

    def test_store_memory_1(self):
        # testing : dst_reg <- m[src_reg]
        binary  = b"\x00\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.StoreMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_store_memory_2(self):
        # testing : dst_reg <- m[src_reg + offset]
        binary  = b"\x33\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4 + 0x33]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.StoreMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_load_add_1(self):
        # testing : dst_reg <- dst_reg + mem[src_reg]
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x03\x00\x80\xe0"                     # 0x00 : (4)  add    r0, r0, r3
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_load_add_2(self):
        # testing : dst_reg <- dst_reg + mem[src_reg + offset]
        binary  = b"\x22\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4, 0x22]
        binary += b"\x03\x00\x80\xe0"                     # 0x00 : (4)  add    r0, r0, r3
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_store_add_1(self):
        # testing : m[dst_reg] <- m[dst_reg] + src_reg
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x03\x30\x80\xe0"                     # 0x00 : (4)  add    r3, r0, r3
        binary += b"\x00\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_store_add_2(self):
        # testing : dst_reg <- dst_reg + mem[src_reg + offset]
        binary  = b"\x22\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4, 0x22]
        binary += b"\x03\x30\x80\xe0"                     # 0x00 : (4)  add    r3, r0, r3
        binary += b"\x22\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4, 0x22]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def _print_candidates(self, candidates):
        print("Candidates :")

        for gadget in candidates:
            print(gadget)
            print("-" * 10)

    def _print_classified(self, classified):
        print("Classified :")

        for gadget in classified:
            print(gadget)
            print(gadget.type)
            print("-" * 10)
class ArmGadgetClassifierTests(unittest.TestCase):

    def setUp(self):

        self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM)
        self._smt_solver = SmtSolver()
        self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size)

        self._ir_emulator = ReilEmulator(self._arch_info)

        self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper)
        self._smt_translator.set_arch_registers_size(self._arch_info.registers_size)

        self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info)

        self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info)
        self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info)

    def _find_and_classify_gadgets(self, binary):
        g_finder = GadgetFinder(ArmDisassembler(architecture_mode=ARCH_ARM_MODE_ARM), bytearray(binary), ArmTranslator(), ARCH_ARM, ARCH_ARM_MODE_ARM)

        g_candidates = g_finder.find(0x00000000, len(binary), instrs_depth=4)
        g_classified = self._g_classifier.classify(g_candidates[0])

#         Debug:
#         self._print_candidates(g_candidates)
#         self._print_classified(g_classified)

        return g_candidates, g_classified

    def test_move_register_1(self):
        # testing : dst_reg <- src_reg
        binary  = b"\x04\x00\xa0\xe1"                     # 0x00 : (4)  mov    r0, r4
        binary += b"\x31\xff\x2f\xe1"                     # 0x04 : (4)  blx    r1

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.MoveRegister)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_move_register_2(self):
        # testing : dst_reg <- src_reg
        binary  = b"\x00\x00\x84\xe2"                     # 0x00 : (4)  add    r0, r4, #0
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.MoveRegister)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    # TODO: test_move_register_n: mul r0, r4, #1

    def test_load_constant_1(self):
        # testing : dst_reg <- constant
        binary  = b"\x0a\x20\xa0\xe3"                     # 0x00 : (4)  mov    r2, #10
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(10, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_2(self):
        # testing : dst_reg <- constant
        binary  = b"\x02\x20\x42\xe0"                     # 0x00 : (4)  sub    r2, r2, r2
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_3(self):
        # testing : dst_reg <- constant
        binary  = b"\x02\x20\x22\xe0"                     # 0x00 : (4)  eor    r2, r2, r2
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_4(self):
        # testing : dst_reg <- constant
        binary  = b"\x00\x20\x02\xe2"                     # 0x00 : (4)  and    r2, r2, #0
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_constant_5(self):
        # testing : dst_reg <- constant
        binary  = b"\x00\x20\x02\xe2"                     # and    r2, r2, #0
        binary += b"\x21\x20\x82\xe3"                     # orr    r2, r2, #33
        binary += b"\x1e\xff\x2f\xe1"                     # bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadConstant)
        self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(33, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)
        self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_add_1(self):
        # testing : dst_reg <- src1_reg + src2_reg
        binary  = b"\x08\x00\x84\xe0"                     # 0x00 : (4)  add    r0, r4, r8
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.Arithmetic)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_sub_1(self):
        # testing : dst_reg <- src1_reg + src2_reg
        binary  = b"\x08\x00\x44\xe0"                     # 0x00 : (4)  sub    r0, r4, r8
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.Arithmetic)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "-")

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_memory_1(self):
        # testing : dst_reg <- m[src_reg]
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_load_memory_2(self):
        # testing : dst_reg <- m[src_reg + offset]
        binary  = b"\x33\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4 + 0x33]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.LoadMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    # TODO: ARM's ldr rd, [rn, r2] is not a valid classification right now

    def test_store_memory_1(self):
        # testing : dst_reg <- m[src_reg]
        binary  = b"\x00\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.StoreMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_store_memory_2(self):
        # testing : dst_reg <- m[src_reg + offset]
        binary  = b"\x33\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4 + 0x33]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 1)

        self.assertEqual(g_classified[0].type, GadgetType.StoreMemory)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)])

        self.assertEqual(len(g_classified[0].modified_registers), 0)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_load_add_1(self):
        # testing : dst_reg <- dst_reg + mem[src_reg]
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x03\x00\x80\xe0"                     # 0x00 : (4)  add    r0, r0, r3
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_load_add_2(self):
        # testing : dst_reg <- dst_reg + mem[src_reg + offset]
        binary  = b"\x22\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4, 0x22]
        binary += b"\x03\x00\x80\xe0"                     # 0x00 : (4)  add    r0, r0, r3
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_store_add_1(self):
        # testing : m[dst_reg] <- m[dst_reg] + src_reg
        binary  = b"\x00\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4]
        binary += b"\x03\x30\x80\xe0"                     # 0x00 : (4)  add    r3, r0, r3
        binary += b"\x00\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def test_arithmetic_store_add_2(self):
        # testing : dst_reg <- dst_reg + mem[src_reg + offset]
        binary  = b"\x22\x30\x94\xe5"                     # 0x00 : (4)  ldr    r3, [r4, 0x22]
        binary += b"\x03\x30\x80\xe0"                     # 0x00 : (4)  add    r3, r0, r3
        binary += b"\x22\x30\x84\xe5"                     # 0x00 : (4)  str    r3, [r4, 0x22]
        binary += b"\x1e\xff\x2f\xe1"                     # 0x04 : (4)  bx     lr

        g_candidates, g_classified = self._find_and_classify_gadgets(binary)

        self.assertEqual(len(g_candidates), 1)
        self.assertEqual(len(g_classified), 2)

        self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore)
        self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32)])
        self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)])
        self.assertEqual(g_classified[0].operation, "+")

        self.assertEqual(len(g_classified[0].modified_registers), 1)

        self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers)
        self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers)

        self.assertTrue(self._g_verifier.verify(g_classified[0]))

    def _print_candidates(self, candidates):
        print("Candidates :")

        for gadget in candidates:
            print(gadget)
            print("-" * 10)

    def _print_classified(self, classified):
        print("Classified :")

        for gadget in classified:
            print(gadget)
            print(gadget.type)
            print("-" * 10)
def barf_classify(gadget_map, printout=True):
    arch_mode = ARCH_X86_MODE_32
    arch_info = X86ArchitectureInformation(arch_mode)
    translator = X86Translator(arch_mode)
    instruction_parser = X86Parser(arch_mode)
    ir_emulator = ReilEmulator(arch_info)
    classifier = GadgetClassifier(ir_emulator, arch_info)
    raw_gadgets = {}
    typed_gadgets = []
    for _, gadget in gadget_map.items():

        # Translation cycle: from my emulator to BARF representation
        classifiable = False
        barf_instr_list = []
        for _, instr in gadget.instructions.items():
            # Parse a ROPInstruction into the BARF representation of an x86 instruction
            barf_instr = instruction_parser.parse("{} {}".format(
                instr.mnemonic, instr.op_str))
            barf_instr.address = instr.address
            try:
                # Translate an x86 instruction into a list of REIL instructions
                reil_transl_instrs = translator.translate(barf_instr)
                barf_instr.ir_instrs = reil_transl_instrs
                classifiable = True
            except TranslationError:
                classifiable = False
            finally:
                barf_instr_list.append(barf_instr)

        # Classification of the gadgets
        barf_g = RawGadget(barf_instr_list)
        raw_gadgets[barf_g.address] = barf_g
        if classifiable:
            classified = classifier.classify(barf_g)
            for tg in classified:
                typed_gadgets.append(tg)
    if printout:
        print_gadgets_raw(list(raw_gadgets.values()), sys.stdout, 'addr', True,
                          'Raw Gadgets', False)
        verified = []
        unverified = []
        solver = Z3Solver()
        translator = SmtTranslator(solver, arch_info.address_size)
        code_analyzer = CodeAnalyzer(solver, translator, arch_info)
        verifier = GadgetVerifier(code_analyzer, arch_info)
        for tg in typed_gadgets:
            if verifier.verify(tg):
                verified.append(tg)
            else:
                unverified.append(tg)
        print_gadgets_typed(verified, sys.stdout, arch_info.address_size,
                            'Verified classification')
        print_gadgets_typed(unverified, sys.stdout, arch_info.address_size,
                            'Unverified classification')
        for tg in typed_gadgets:
            if tg.address in raw_gadgets:
                raw_gadgets.pop(tg.address)
        print_gadgets_raw(list(raw_gadgets.values()), sys.stdout, 'addr',
                          False, 'Not classified', False)

    return {tg.address: tg for tg in typed_gadgets}