[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