xref: /llvm-project/lldb/test/API/tools/lldb-server/TestGdbRemoteRegisterState.py (revision 9c2468821ec51defd09c246fea4a47886fff8c01)
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(inferior_args=inferior_args)
14
15        self.add_process_info_collection_packets()
16        self.add_register_info_collection_packets()
17        if with_suffix:
18            self.add_thread_suffix_request_packets()
19        self.add_threadinfo_collection_packets()
20
21        context = self.expect_gdbremote_sequence()
22        self.assertIsNotNone(context)
23
24        # Gather process info.
25        process_info = self.parse_process_info_response(context)
26        endian = process_info.get("endian")
27        self.assertIsNotNone(endian)
28
29        # Gather register info.
30        reg_infos = self.parse_register_info_packets(context)
31        self.assertIsNotNone(reg_infos)
32        self.add_lldb_register_index(reg_infos)
33
34        # Pull out the register infos that we think we can bit flip
35        # successfully.
36        gpr_reg_infos = [
37            reg_info
38            for reg_info in reg_infos
39            if self.is_bit_flippable_register(reg_info)
40        ]
41        self.assertGreater(len(gpr_reg_infos), 0)
42
43        # Gather thread info.
44        if with_suffix:
45            threads = self.parse_threadinfo_packets(context)
46            self.assertIsNotNone(threads)
47            thread_id = threads[0]
48            self.assertIsNotNone(thread_id)
49            self.trace("Running on thread: 0x{:x}".format(thread_id))
50        else:
51            thread_id = None
52
53        # Save register state.
54        self.reset_test_sequence()
55        self.add_QSaveRegisterState_packets(thread_id)
56
57        context = self.expect_gdbremote_sequence()
58        self.assertIsNotNone(context)
59
60        (success, state_id) = self.parse_QSaveRegisterState_response(context)
61        self.assertTrue(success)
62        self.assertIsNotNone(state_id)
63        self.trace("saved register state id: {}".format(state_id))
64
65        # Remember initial register values.
66        initial_reg_values = self.read_register_values(
67            gpr_reg_infos, endian, thread_id=thread_id
68        )
69        self.trace("initial_reg_values: {}".format(initial_reg_values))
70
71        # Flip gpr register values.
72        (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(
73            gpr_reg_infos, endian, thread_id=thread_id
74        )
75        self.trace(
76            "successful writes: {}, failed writes: {}".format(
77                successful_writes, failed_writes
78            )
79        )
80        self.assertGreater(successful_writes, 0)
81
82        flipped_reg_values = self.read_register_values(
83            gpr_reg_infos, endian, thread_id=thread_id
84        )
85        self.trace("flipped_reg_values: {}".format(flipped_reg_values))
86
87        # Restore register values.
88        self.reset_test_sequence()
89        self.add_QRestoreRegisterState_packets(state_id, thread_id)
90
91        context = self.expect_gdbremote_sequence()
92        self.assertIsNotNone(context)
93
94        # Verify registers match initial register values.
95        final_reg_values = self.read_register_values(
96            gpr_reg_infos, endian, thread_id=thread_id
97        )
98        self.trace("final_reg_values: {}".format(final_reg_values))
99        self.assertIsNotNone(final_reg_values)
100        self.assertEqual(final_reg_values, initial_reg_values)
101
102    def test_grp_register_save_restore_works_with_suffix(self):
103        USE_THREAD_SUFFIX = True
104        self.build()
105        self.set_inferior_startup_launch()
106        self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
107
108    def test_grp_register_save_restore_works_no_suffix(self):
109        USE_THREAD_SUFFIX = False
110        self.build()
111        self.set_inferior_startup_launch()
112        self.grp_register_save_restore_works(USE_THREAD_SUFFIX)
113