1import gdbremote_testcase
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6
7class TestGdbRemoteRegisterState(gdbremote_testcase.GdbRemoteTestCaseBase):
8    """Test QSaveRegisterState/QRestoreRegisterState support."""
9
10    def grp_register_save_restore_works(self, with_suffix):
11        # Start up the process, use thread suffix, grab main thread id.
12        inferior_args = ["message:main entered", "sleep:5"]
13        procs = self.prep_debug_monitor_and_inferior(
14            inferior_args=inferior_args)
15
16        self.add_process_info_collection_packets()
17        self.add_register_info_collection_packets()
18        if with_suffix:
19            self.add_thread_suffix_request_packets()
20        self.add_threadinfo_collection_packets()
21
22        context = self.expect_gdbremote_sequence()
23        self.assertIsNotNone(context)
24
25        # Gather process info.
26        process_info = self.parse_process_info_response(context)
27        endian = process_info.get("endian")
28        self.assertIsNotNone(endian)
29
30        # Gather register info.
31        reg_infos = self.parse_register_info_packets(context)
32        self.assertIsNotNone(reg_infos)
33        self.add_lldb_register_index(reg_infos)
34
35        # Pull out the register infos that we think we can bit flip
36        # successfully.
37        gpr_reg_infos = [
38            reg_info for reg_info in reg_infos if self.is_bit_flippable_register(reg_info)]
39        self.assertTrue(len(gpr_reg_infos) > 0)
40
41        # Gather thread info.
42        if with_suffix:
43            threads = self.parse_threadinfo_packets(context)
44            self.assertIsNotNone(threads)
45            thread_id = threads[0]
46            self.assertIsNotNone(thread_id)
47            self.trace("Running on thread: 0x{:x}".format(thread_id))
48        else:
49            thread_id = None
50
51        # Save register state.
52        self.reset_test_sequence()
53        self.add_QSaveRegisterState_packets(thread_id)
54
55        context = self.expect_gdbremote_sequence()
56        self.assertIsNotNone(context)
57
58        (success, state_id) = self.parse_QSaveRegisterState_response(context)
59        self.assertTrue(success)
60        self.assertIsNotNone(state_id)
61        self.trace("saved register state id: {}".format(state_id))
62
63        # Remember initial register values.
64        initial_reg_values = self.read_register_values(
65            gpr_reg_infos, endian, thread_id=thread_id)
66        self.trace("initial_reg_values: {}".format(initial_reg_values))
67
68        # Flip gpr register values.
69        (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
70            gpr_reg_infos, endian, thread_id=thread_id)
71        self.trace("successful writes: {}, failed writes: {}".format(successful_writes, failed_writes))
72        self.assertTrue(successful_writes > 0)
73
74        flipped_reg_values = self.read_register_values(
75            gpr_reg_infos, endian, thread_id=thread_id)
76        self.trace("flipped_reg_values: {}".format(flipped_reg_values))
77
78        # Restore register values.
79        self.reset_test_sequence()
80        self.add_QRestoreRegisterState_packets(state_id, thread_id)
81
82        context = self.expect_gdbremote_sequence()
83        self.assertIsNotNone(context)
84
85        # Verify registers match initial register values.
86        final_reg_values = self.read_register_values(
87            gpr_reg_infos, endian, thread_id=thread_id)
88        self.trace("final_reg_values: {}".format(final_reg_values))
89        self.assertIsNotNone(final_reg_values)
90        self.assertEqual(final_reg_values, initial_reg_values)
91
92    def test_grp_register_save_restore_works_with_suffix(self):
93        USE_THREAD_SUFFIX = True
94        self.build()
95        self.set_inferior_startup_launch()
96        self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
97
98    def test_grp_register_save_restore_works_no_suffix(self):
99        USE_THREAD_SUFFIX = False
100        self.build()
101        self.set_inferior_startup_launch()
102        self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
103