def testSingleEntry(self): self.maxDiff = None complete_instruction_sequence0 = bytes([3]) complete_instruction_sequence1 = bytes([1, 3]) sequence1 = ( EncodedAddressUnwind(0x200, complete_instruction_sequence1), EncodedAddressUnwind(0x0, complete_instruction_sequence0), ) address_unwind_sequences = [sequence1] table, offsets = EncodeFunctionOffsetTable( address_unwind_sequences, { complete_instruction_sequence0: 52, complete_instruction_sequence1: 50, }) self.assertEqual( bytes([ # (0x200, 50) 128, 4, 50, # (0, 52) 0, 52, ]), table) self.assertDictEqual({ sequence1: 0, }, offsets)
def testFillingFirstPage(self, MockEncodeAddressUnwinds): MockEncodeAddressUnwinds.return_value = EncodedAddressUnwind( 0, b'\x00') self.assertEqual( [ EncodedFunctionUnwind(page_number=0, page_offset=0, address_unwinds=REFUSE_TO_UNWIND), EncodedFunctionUnwind(page_number=0, page_offset=100 >> 1, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), EncodedFunctionUnwind(page_number=0, page_offset=200 >> 1, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), EncodedFunctionUnwind(page_number=0, page_offset=300 >> 1, address_unwinds=REFUSE_TO_UNWIND), ], list( EncodeFunctionUnwinds([ FunctionUnwind(address=1100, size=100, address_unwinds=()), FunctionUnwind(address=1200, size=100, address_unwinds=()), ], text_section_start_address=1000)))
def testFillingGaps(self, MockEncodeAddressUnwinds): MockEncodeAddressUnwinds.return_value = EncodedAddressUnwind( 0, b'\x00') self.assertEqual( [ EncodedFunctionUnwind(page_number=0, page_offset=0, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), EncodedFunctionUnwind(page_number=0, page_offset=50 >> 1, address_unwinds=TRIVIAL_UNWIND), EncodedFunctionUnwind(page_number=0, page_offset=100 >> 1, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), ], list( EncodeFunctionUnwinds([ FunctionUnwind(address=0, size=50, address_unwinds=()), FunctionUnwind( address=100, size=PAGE_SIZE - 100, address_unwinds=()), ], text_section_start_address=0)))
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 testDuplicatedEntry(self): self.maxDiff = None complete_instruction_sequence0 = bytes([3]) complete_instruction_sequence1 = bytes([1, 3]) complete_instruction_sequence2 = bytes([2, 3]) sequence1 = ( EncodedAddressUnwind(0x10, complete_instruction_sequence1), EncodedAddressUnwind(0x0, complete_instruction_sequence0), ) sequence2 = ( EncodedAddressUnwind(0x200, complete_instruction_sequence2), EncodedAddressUnwind(0x0, complete_instruction_sequence0), ) sequence3 = sequence1 address_unwind_sequences = [sequence1, sequence2, sequence3] table, offsets = EncodeFunctionOffsetTable( address_unwind_sequences, { complete_instruction_sequence0: 52, complete_instruction_sequence1: 50, complete_instruction_sequence2: 80, }) self.assertEqual( bytes([ # (0x10, 50) 0x10, 50, # (0, 52) 0, 52, # (0x200, 80) 128, 4, 80, # (0, 52) 0, 52, ]), table) self.assertDictEqual({ sequence1: 0, sequence2: 4, }, offsets)
def testEncodeOrder(self, MockEncodeAddressUnwinds): MockEncodeAddressUnwinds.return_value = EncodedAddressUnwind( 0, b'\x00') self.assertEqual([ EncodedFunctionUnwind(page_number=0, page_offset=0, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), EncodedFunctionUnwind(page_number=0, page_offset=100 >> 1, address_unwinds=EncodedAddressUnwind( 0, b'\x00')), ], list( EncodeFunctionUnwinds([ FunctionUnwind(address=100, size=PAGE_SIZE - 100, address_unwinds=()), FunctionUnwind(address=0, size=100, address_unwinds=()), ])))
def testMultiPageFunction(self): address_unwind_sequence0 = ( EncodedAddressUnwind(0x10, bytes([0, 3])), EncodedAddressUnwind(0x0, bytes([3])), ) address_unwind_sequence1 = ( EncodedAddressUnwind(0x10, bytes([1, 3])), EncodedAddressUnwind(0x0, bytes([3])), ) address_unwind_sequence2 = ( EncodedAddressUnwind(0x200, bytes([2, 3])), EncodedAddressUnwind(0x0, bytes([3])), ) function_unwinds = [ EncodedFunctionUnwind(page_number=0, page_offset=0, address_unwinds=address_unwind_sequence0), # Large function. EncodedFunctionUnwind(page_number=0, page_offset=0x8000, address_unwinds=address_unwind_sequence1), EncodedFunctionUnwind(page_number=4, page_offset=0x8000, address_unwinds=address_unwind_sequence2), ] function_offset_table_offsets = { address_unwind_sequence0: 0x100, address_unwind_sequence1: 0x200, address_unwind_sequence2: 0x300, } page_table, function_table = EncodePageTableAndFunctionTable( function_unwinds, function_offset_table_offsets) self.assertEqual(5 * 4, len(page_table)) self.assertEqual((0, 2, 2, 2, 2), struct.unpack('5I', page_table)) self.assertEqual(6 * 2, len(function_table)) self.assertEqual((0, 0x100, 0x8000, 0x200, 0x8000, 0x300), struct.unpack('6H', function_table))
def testGenerateUnwindTables(self): """This is an integration test that hooks everything together. """ address_unwind_sequence0 = ( EncodedAddressUnwind(0x10, bytes([0, 0xb0])), EncodedAddressUnwind(0x0, bytes([0xb0])), ) address_unwind_sequence1 = ( EncodedAddressUnwind(0x10, bytes([1, 0xb0])), EncodedAddressUnwind(0x0, bytes([0xb0])), ) address_unwind_sequence2 = ( EncodedAddressUnwind(0x100, bytes([2, 0xb0])), EncodedAddressUnwind(0x0, bytes([0xb0])), ) (page_table, function_table, function_offset_table, unwind_instruction_table) = GenerateUnwindTables([ EncodedFunctionUnwind(page_number=0, page_offset=0, address_unwinds=TRIVIAL_UNWIND), EncodedFunctionUnwind(page_number=0, page_offset=0x1000, address_unwinds=address_unwind_sequence0), EncodedFunctionUnwind(page_number=1, page_offset=0x2000, address_unwinds=address_unwind_sequence1), EncodedFunctionUnwind(page_number=3, page_offset=0x1000, address_unwinds=address_unwind_sequence2), ]) # Complete instruction sequences and their frequencies. # [0xb0]: 4 # [0, 0xb0]: 1 # [1, 0xb0]: 1 # [2, 0xb0]: 1 self.assertEqual(bytes([0xb0, 2, 0xb0, 1, 0xb0, 0, 0xb0]), unwind_instruction_table) self.assertEqual( bytes([ # Trivial unwind. 0, 0, # Address unwind sequence 0. 0x10, 5, 0, 0, # Address unwind sequence 1. 0x10, 3, 0, 0, # Address unwind sequence 2. 0x80, 2, 1, 0, 0, ]), function_offset_table) self.assertEqual(8 * 2, len(function_table)) self.assertEqual((0, 0, 0x1000, 2, 0x2000, 6, 0x1000, 10), struct.unpack('8H', function_table)) self.assertEqual(4 * 4, len(page_table)) self.assertEqual((0, 2, 3, 3), struct.unpack('4I', page_table))