| from __future__ import print_function |
| |
| |
| import gdbremote_testcase |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test import lldbutil |
| |
| |
| class TestGdbRemoteRegisterState(gdbremote_testcase.GdbRemoteTestCaseBase): |
| """Test QSaveRegisterState/QRestoreRegisterState support.""" |
| |
| mydir = TestBase.compute_mydir(__file__) |
| |
| @skipIfDarwinEmbedded # <rdar://problem/34539270> lldb-server tests not updated to work on ios etc yet |
| def grp_register_save_restore_works(self, with_suffix): |
| # Start up the process, use thread suffix, grab main thread id. |
| inferior_args = ["message:main entered", "sleep:5"] |
| procs = self.prep_debug_monitor_and_inferior( |
| inferior_args=inferior_args) |
| |
| self.add_process_info_collection_packets() |
| self.add_register_info_collection_packets() |
| if with_suffix: |
| self.add_thread_suffix_request_packets() |
| self.add_threadinfo_collection_packets() |
| self.test_sequence.add_log_lines([ |
| # Start the inferior... |
| "read packet: $c#63", |
| # ... match output.... |
| {"type": "output_match", "regex": self.maybe_strict_output_regex( |
| r"message:main entered\r\n")}, |
| ], True) |
| # ... then interrupt. |
| self.add_interrupt_packets() |
| |
| context = self.expect_gdbremote_sequence() |
| self.assertIsNotNone(context) |
| |
| # Gather process info. |
| process_info = self.parse_process_info_response(context) |
| endian = process_info.get("endian") |
| self.assertIsNotNone(endian) |
| |
| # Gather register info. |
| reg_infos = self.parse_register_info_packets(context) |
| self.assertIsNotNone(reg_infos) |
| self.add_lldb_register_index(reg_infos) |
| |
| # Pull out the register infos that we think we can bit flip |
| # successfully. |
| gpr_reg_infos = [ |
| reg_info for reg_info in reg_infos if self.is_bit_flippable_register(reg_info)] |
| self.assertTrue(len(gpr_reg_infos) > 0) |
| |
| # Gather thread info. |
| if with_suffix: |
| threads = self.parse_threadinfo_packets(context) |
| self.assertIsNotNone(threads) |
| thread_id = threads[0] |
| self.assertIsNotNone(thread_id) |
| # print("Running on thread: 0x{:x}".format(thread_id)) |
| else: |
| thread_id = None |
| |
| # Save register state. |
| self.reset_test_sequence() |
| self.add_QSaveRegisterState_packets(thread_id) |
| |
| context = self.expect_gdbremote_sequence() |
| self.assertIsNotNone(context) |
| |
| (success, state_id) = self.parse_QSaveRegisterState_response(context) |
| self.assertTrue(success) |
| self.assertIsNotNone(state_id) |
| # print("saved register state id: {}".format(state_id)) |
| |
| # Remember initial register values. |
| initial_reg_values = self.read_register_values( |
| gpr_reg_infos, endian, thread_id=thread_id) |
| # print("initial_reg_values: {}".format(initial_reg_values)) |
| |
| # Flip gpr register values. |
| (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value( |
| gpr_reg_infos, endian, thread_id=thread_id) |
| # print("successful writes: {}, failed writes: {}".format(successful_writes, failed_writes)) |
| self.assertTrue(successful_writes > 0) |
| |
| flipped_reg_values = self.read_register_values( |
| gpr_reg_infos, endian, thread_id=thread_id) |
| # print("flipped_reg_values: {}".format(flipped_reg_values)) |
| |
| # Restore register values. |
| self.reset_test_sequence() |
| self.add_QRestoreRegisterState_packets(state_id, thread_id) |
| |
| context = self.expect_gdbremote_sequence() |
| self.assertIsNotNone(context) |
| |
| # Verify registers match initial register values. |
| final_reg_values = self.read_register_values( |
| gpr_reg_infos, endian, thread_id=thread_id) |
| # print("final_reg_values: {}".format(final_reg_values)) |
| self.assertIsNotNone(final_reg_values) |
| self.assertEqual(final_reg_values, initial_reg_values) |
| |
| @debugserver_test |
| def test_grp_register_save_restore_works_with_suffix_debugserver(self): |
| USE_THREAD_SUFFIX = True |
| self.init_debugserver_test() |
| self.build() |
| self.set_inferior_startup_launch() |
| self.grp_register_save_restore_works(USE_THREAD_SUFFIX) |
| |
| @llgs_test |
| def test_grp_register_save_restore_works_with_suffix_llgs(self): |
| USE_THREAD_SUFFIX = True |
| self.init_llgs_test() |
| self.build() |
| self.set_inferior_startup_launch() |
| self.grp_register_save_restore_works(USE_THREAD_SUFFIX) |
| |
| @debugserver_test |
| def test_grp_register_save_restore_works_no_suffix_debugserver(self): |
| USE_THREAD_SUFFIX = False |
| self.init_debugserver_test() |
| self.build() |
| self.set_inferior_startup_launch() |
| self.grp_register_save_restore_works(USE_THREAD_SUFFIX) |
| |
| @llgs_test |
| def test_grp_register_save_restore_works_no_suffix_llgs(self): |
| USE_THREAD_SUFFIX = False |
| self.init_llgs_test() |
| self.build() |
| self.set_inferior_startup_launch() |
| self.grp_register_save_restore_works(USE_THREAD_SUFFIX) |