[Lldb-commits] [lldb] r210681 - Add gdb-remote P register write test.

Todd Fiala todd.fiala at gmail.com
Wed Jun 11 11:09:01 PDT 2014


Author: tfiala
Date: Wed Jun 11 13:09:01 2014
New Revision: 210681

URL: http://llvm.org/viewvc/llvm-project?rev=210681&view=rev
Log:
Add gdb-remote P register write test.

Added test that attempts to write a value to each general
purpose register that is bit-flipped from the initial read
value.  It then reads it back to see if it takes.

Right now I just assert that at least one register bit flip
write succeeds.  I added a note that on the MacOSX x86_64
debugserver case, the only writes that succeed from the GPR
set are rax thru rdx, rdi, rsi and rbp.  The failures are E32
failure-at-write-attempt issues on the debugserver end.
I'll revisit this after implementing in the llgs linux-x86_64 branch.
The packet log looks good but I may have a subtle mistake in the code.

Modified:
    lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=210681&r1=210680&r2=210681&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Wed Jun 11 13:09:01 2014
@@ -49,7 +49,7 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
 
         # Uncomment this code to force only a single test to run (by name).
-        # if not re.search(r"written_M", self._testMethodName):
+        # if not re.search(r"P_writes", self._testMethodName):
         #     self.skipTest("focusing on one test")
 
     def reset_test_sequence(self):
@@ -295,6 +295,19 @@ class LldbGdbServerTestCase(TestBase):
 
         return (None, None)
 
+    def add_lldb_register_index(self, reg_infos):
+        """Add a "lldb_register_index" key containing the 0-baed index of each reg_infos entry.
+
+        We'll use this when we want to call packets like P/p with a register index but do so
+        on only a subset of the full register info set.
+        """
+        self.assertIsNotNone(reg_infos)
+
+        reg_index = 0
+        for reg_info in reg_infos:
+            reg_info["lldb_register_index"] = reg_index
+            reg_index += 1
+
     def add_query_memory_region_packets(self, address):
         self.test_sequence.add_log_lines(
             ["read packet: $qMemoryRegionInfo:{0:x}#00".format(address),
@@ -2019,6 +2032,121 @@ class LldbGdbServerTestCase(TestBase):
         self.set_inferior_startup_launch()
         self.written_M_content_reads_back_correctly()
 
+    def flip_all_bits_in_each_register_value(self, reg_infos):
+        self.assertIsNotNone(reg_infos)
+
+        successful_writes = 0
+        failed_writes = 0
+
+        for reg_info in reg_infos:
+            # Use the lldb register index added to the reg info.  We're not necessarily
+            # working off a full set of register infos, so an inferred register index could be wrong. 
+            reg_index = reg_info["lldb_register_index"]
+            self.assertIsNotNone(reg_index)
+
+            # Read the existing value.
+            self.reset_test_sequence()
+            self.test_sequence.add_log_lines(
+                ["read packet: $p{0:x}#00".format(reg_index),
+                 { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} }],
+                True)
+            context = self.expect_gdbremote_sequence()
+            self.assertIsNotNone(context)
+
+            # Verify the response length.
+            p_response = context.get("p_response")
+            self.assertIsNotNone(p_response)
+            self.assertEquals(len(p_response), 2 * int(reg_info["bitsize"]) / 8)
+
+            # Flip the value by xoring with all 1s
+            all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
+            flipped_bits_int = int(p_response, 16) ^ int(all_one_bits_raw, 16)
+            # print "reg (index={}, name={}): val={}, flipped bits (int={}, hex={:x})".format(reg_index, reg_info["name"], p_response, flipped_bits_int, flipped_bits_int)
+
+            # Write the flipped value to the register.
+            self.reset_test_sequence()
+            self.test_sequence.add_log_lines(
+                ["read packet: $P{0:x}={1:x}#00".format(reg_index, flipped_bits_int),
+                { "direction":"send", "regex":r"^\$(OK|E[0-9a-fA-F]+)#[0-9a-fA-F]{2}", "capture":{1:"P_response"} },
+                ], True)
+            context = self.expect_gdbremote_sequence()
+            self.assertIsNotNone(context)
+
+            # Determine if the write succeeded.  There are a handful of registers that can fail.
+            P_response = context.get("P_response")
+            self.assertIsNotNone(P_response)
+            if P_response == "OK":
+                successful_writes += 1
+            else:
+                failed_writes += 1
+                # print "reg (index={}, name={}) write FAILED (error: {})".format(reg_index, reg_info["name"], P_response)
+
+            # Read back the register value, ensure it matches the flipped value.
+            if P_response == "OK":
+                self.reset_test_sequence()
+                self.test_sequence.add_log_lines(
+                    ["read packet: $p{0:x}#00".format(reg_index),
+                     { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} }],
+                    True)
+                context = self.expect_gdbremote_sequence()
+                self.assertIsNotNone(context)
+
+                verify_p_response = context.get("p_response")
+                self.assertIsNotNone(verify_p_response)
+                if verify_p_response != "{:x}".format(flipped_bits_int):
+                    # Some registers, like mxcsrmask and others, will permute what's written.  Adjust succeed/fail counts.
+                    # print "reg (index={}, name={}): read verify FAILED: wrote {:x}, verify read back {}".format(reg_index, reg_info["name"], flipped_bits_int, verify_p_response)
+                    successful_writes -= 1
+                    failed_writes +=1
+
+        return (successful_writes, failed_writes)
+
+    def P_writes_all_gpr_registers(self):
+        # Start inferior debug session, grab all register info.
+        procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])
+        self.add_register_info_collection_packets()
+        self.test_sequence.add_log_lines(
+            [# Start running for a bit.
+             "read packet: $c#00",
+             "read packet: {}".format(chr(03)),
+             {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+            True)
+
+        context = self.expect_gdbremote_sequence()
+        self.assertIsNotNone(context)
+
+        reg_infos = self.parse_register_info_packets(context)
+        self.assertIsNotNone(reg_infos)
+        self.add_lldb_register_index(reg_infos)
+
+        # Pull out the general purpose register infos
+        gpr_reg_infos = [reg_info for reg_info in reg_infos if reg_info["set"] == "General Purpose Registers"]
+        self.assertIsNotNone(len(gpr_reg_infos) > 0)
+
+        # Write flipped bit pattern of existing value to each register.
+        (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(gpr_reg_infos)
+        # print "successful writes: {}, failed writes: {}".format(successful_writes, failed_writes)
+        self.assertTrue(successful_writes > 0)
+
+    # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).
+    # Come back to this.  I have the test rigged to verify that at least some of the bit-flip writes work.
+    @debugserver_test
+    @dsym_test
+    def test_P_writes_all_gpr_registers_debugserver_dsym(self):
+        self.init_debugserver_test()
+        self.buildDsym()
+        self.set_inferior_startup_launch()
+        self.P_writes_all_gpr_registers()
+
+    @llgs_test
+    @dwarf_test
+    @unittest2.expectedFailure()
+    def test_P_writes_all_gpr_registers_llgs_dwarf(self):
+        self.init_llgs_test()
+        self.buildDwarf()
+        self.set_inferior_startup_launch()
+        self.P_writes_all_gpr_registers()
+
 
 if __name__ == '__main__':
     unittest2.main()





More information about the lldb-commits mailing list