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.

llvm-svn: 210681
This commit is contained in:
Todd Fiala 2014-06-11 18:09:01 +00:00
parent caa0ec2851
commit 5cc2417532
1 changed files with 129 additions and 1 deletions

View File

@ -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()