def testEncodeOrder(self): address_unwind1 = AddressUnwind(address_offset=0, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=tuple()) address_unwind2 = AddressUnwind( address_offset=4, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=0, registers=(4, 14)) def MockEncodeAddressUnwind(address_unwind): return { address_unwind1: bytes([1]), address_unwind2: bytes([2]), }[address_unwind] with unittest.mock.patch("create_unwind_table.EncodeAddressUnwind", side_effect=MockEncodeAddressUnwind): encoded_unwinds = EncodeAddressUnwinds( (address_unwind1, address_unwind2)) self.assertEqual(( EncodedAddressUnwind(4, bytes([2]) + bytes([1])), EncodedAddressUnwind(0, bytes([1])), ), encoded_unwinds)
def testUpdateSpAndOrPopRegisters(self): self.assertEqual( bytes([0b0, 0b10101000]), EncodeAddressUnwind( AddressUnwind( address_offset=0, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=0x4, registers=(4, 14)))) self.assertEqual( bytes([0b0]), EncodeAddressUnwind( AddressUnwind( address_offset=0, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=0x4, registers=tuple()))) self.assertEqual( bytes([0b10101000]), EncodeAddressUnwind( AddressUnwind( address_offset=0, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=0, registers=(4, 14))))
def testSuccessUnwind(self): self.assertEqual( [ FunctionUnwind(address=0x100, size=1024, address_unwinds=( AddressUnwind( address_offset=0x0, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=(), ), AddressUnwind( address_offset=0x200, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=(), ), )) ], list( GenerateUnwinds([ FunctionCfi(size=1024, address_cfi=( AddressCfi(address=0x100, unwind_instructions='RETURN'), AddressCfi(address=0x300, unwind_instructions='RETURN'), )) ], parsers=[MockReturnParser()])))
def testReturnToLr(self): self.assertEqual( bytes([0b10110000]), EncodeAddressUnwind( AddressUnwind(address_offset=0, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=tuple())))
def testNoAction(self): self.assertEqual( bytes([]), EncodeAddressUnwind( AddressUnwind(address_offset=0, unwind_type=UnwindType.NO_ACTION, sp_offset=0, registers=tuple())))
def testCfaAndRegistersChange(self): parser = StoreSpParser() match = parser.GetBreakpadInstructionsRegex().search('.cfa: r7 8 +') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=12, match=match) self.assertEqual(8, new_cfa_sp_offset) self.assertEqual( AddressUnwind(address_offset=20, unwind_type=UnwindType.RESTORE_SP_FROM_REGISTER, sp_offset=-4, registers=(7, )), address_unwind)
def testRestoreSpFromRegisters(self): self.assertEqual( bytes([0b10010100, 0b0]), EncodeAddressUnwind( AddressUnwind(address_offset=0, unwind_type=UnwindType.RESTORE_SP_FROM_REGISTER, sp_offset=0x4, registers=(4, )))) self.assertEqual( bytes([0b10010100]), EncodeAddressUnwind( AddressUnwind(address_offset=0, unwind_type=UnwindType.RESTORE_SP_FROM_REGISTER, sp_offset=0, registers=(4, )))) self.assertRaises( AssertionError, lambda: EncodeAddressUnwind( AddressUnwind(address_offset=0, unwind_type=UnwindType.RESTORE_SP_FROM_REGISTER, sp_offset=0x4, registers=tuple())))
def testParsePrecedence(self): address_unwind = AddressUnwind( address_offset=0x300, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=(), ) self.assertEqual( (address_unwind, False, 0), ParseAddressCfi(AddressCfi(address=0x800, unwind_instructions='RETURN'), function_start_address=0x500, parsers=(MockReturnParser(), MockWildcardParser()), prev_cfa_sp_offset=0))
def testCfaChange(self): parser = PushOrSubSpParser() match = parser.GetBreakpadInstructionsRegex().search('.cfa: sp 4 +') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=0, match=match) self.assertEqual(4, new_cfa_sp_offset) self.assertEqual( AddressUnwind( address_offset=20, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=4, registers=()), address_unwind)
def testCfaChange(self): parser = NullParser() match = parser.GetBreakpadInstructionsRegex().search( '.cfa: sp 0 + .ra: lr') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=0, cfa_sp_offset=0, match=match) self.assertEqual(0, new_cfa_sp_offset) self.assertEqual( AddressUnwind(address_offset=0, unwind_type=UnwindType.RETURN_TO_LR, sp_offset=0, registers=()), address_unwind)
def testRegistersOrdering(self): parser = PushOrSubSpParser() match = parser.GetBreakpadInstructionsRegex().search( 'r10: .cfa -8 + ^ r7: .cfa -4 + ^') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=0, match=match) self.assertEqual(0, new_cfa_sp_offset) self.assertEqual( AddressUnwind( address_offset=20, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=0, registers=(7, 10)), address_unwind)
def testRegistersChange(self): parser = VPushParser() match = parser.GetBreakpadInstructionsRegex().search( 'unnamed_register264: .cfa -40 + ^ unnamed_register265: .cfa -32 + ^' ) self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=24, match=match) self.assertEqual(24, new_cfa_sp_offset) self.assertEqual( AddressUnwind(address_offset=20, unwind_type=UnwindType.NO_ACTION, sp_offset=0, registers=()), address_unwind)
def testCfaAndRaAndRegistersChangePopAndSpUpdate(self): parser = PushOrSubSpParser() match = parser.GetBreakpadInstructionsRegex().search( '.cfa: sp 16 + .ra: .cfa -4 + ^ r4: .cfa -12 + ^ r7: .cfa -8 + ^') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=0, match=match) self.assertEqual(16, new_cfa_sp_offset) self.assertEqual( AddressUnwind( address_offset=20, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=4, registers=(4, 7, 14)), address_unwind)
def testCfaAndRegistersChange(self): parser = VPushParser() match = parser.GetBreakpadInstructionsRegex().search( '.cfa: sp 40 + unnamed_register264: .cfa -40 + ^ ' 'unnamed_register265: .cfa -32 + ^') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=24, match=match) self.assertEqual(40, new_cfa_sp_offset) self.assertEqual( AddressUnwind( address_offset=20, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=16, registers=()), address_unwind)
def testPoppingCallerSaveRegisters(self): """Regression test for pop unwinds that encode caller-save registers. Callee-save registers: r0 ~ r3. """ parser = PushOrSubSpParser() match = parser.GetBreakpadInstructionsRegex().search( '.cfa: sp 16 + .ra: .cfa -4 + ^ ' 'r3: .cfa -16 + ^ r4: .cfa -12 + ^ r5: .cfa -8 + ^') self.assertIsNotNone(match) address_unwind, new_cfa_sp_offset = parser.ParseFromMatch( address_offset=20, cfa_sp_offset=0, match=match) self.assertEqual(16, new_cfa_sp_offset) self.assertEqual( AddressUnwind( address_offset=20, unwind_type=UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, sp_offset=4, registers=(4, 5, 14)), address_unwind)
def ParseFromMatch(self, address_offset, cfa_sp_offset, match): return AddressUnwind(address_offset, UnwindType.UPDATE_SP_AND_OR_POP_REGISTERS, 0, ()), -200
def ParseFromMatch(self, address_offset, cfa_sp_offset, match): return AddressUnwind(address_offset, UnwindType.RETURN_TO_LR, 0, ()), 0