summaryrefslogtreecommitdiffstats
path: root/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py')
-rw-r--r--lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py177
1 files changed, 176 insertions, 1 deletions
diff --git a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py
index 653ba0c0be4..de9b4818717 100644
--- a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py
+++ b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py
@@ -676,4 +676,179 @@ class GdbRemoteTestCaseBase(TestBase):
def parse_interrupt_packets(self, context):
self.assertIsNotNone(context.get("stop_signo"))
self.assertIsNotNone(context.get("stop_key_val_text"))
- return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"])) \ No newline at end of file
+ return (int(context["stop_signo"], 16), self.parse_key_val_dict(context["stop_key_val_text"]))
+
+ def add_QSaveRegisterState_packets(self, thread_id):
+ if thread_id:
+ # Use the thread suffix form.
+ request = "read packet: $QSaveRegisterState;thread:{:x}#00".format(thread_id)
+ else:
+ request = "read packet: $QSaveRegisterState#00"
+
+ self.test_sequence.add_log_lines([
+ request,
+ {"direction":"send", "regex":r"^\$(E?.*)#[0-9a-fA-F]{2}$", "capture":{1:"save_response" } },
+ ], True)
+
+ def parse_QSaveRegisterState_response(self, context):
+ self.assertIsNotNone(context)
+
+ save_response = context.get("save_response")
+ self.assertIsNotNone(save_response)
+
+ if len(save_response) < 1 or save_response[0] == "E":
+ # error received
+ return (False, None)
+ else:
+ return (True, int(save_response))
+
+ def add_QRestoreRegisterState_packets(self, save_id, thread_id=None):
+ if thread_id:
+ # Use the thread suffix form.
+ request = "read packet: $QRestoreRegisterState:{};thread:{:x}#00".format(save_id, thread_id)
+ else:
+ request = "read packet: $QRestoreRegisterState:{}#00".format(save_id)
+
+ self.test_sequence.add_log_lines([
+ request,
+ "send packet: $OK#00"
+ ], True)
+
+ def flip_all_bits_in_each_register_value(self, reg_infos, endian, thread_id=None):
+ 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)
+
+ reg_byte_size = int(reg_info["bitsize"])/8
+ self.assertTrue(reg_byte_size > 0)
+
+ # Handle thread suffix.
+ if thread_id:
+ p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
+ else:
+ p_request = "read packet: $p{:x}#00".format(reg_index)
+
+ # Read the existing value.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ p_request,
+ { "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)
+ initial_reg_value = unpack_register_hex_unsigned(endian, p_response)
+
+ # Flip the value by xoring with all 1s
+ all_one_bits_raw = "ff" * (int(reg_info["bitsize"]) / 8)
+ flipped_bits_int = initial_reg_value ^ int(all_one_bits_raw, 16)
+ # print "reg (index={}, name={}): val={}, flipped bits (int={}, hex={:x})".format(reg_index, reg_info["name"], initial_reg_value, flipped_bits_int, flipped_bits_int)
+
+ # Handle thread suffix for P.
+ if thread_id:
+ P_request = "read packet: $P{:x}={};thread:{:x}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size), thread_id)
+ else:
+ P_request = "read packet: $P{:x}={}#00".format(reg_index, pack_register_hex(endian, flipped_bits_int, byte_size=reg_byte_size))
+
+ # Write the flipped value to the register.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ P_request,
+ { "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, or partially fail
+ # (e.g. flags, segment selectors, etc.) due to register value restrictions. Don't worry about them
+ # all flipping perfectly.
+ 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([
+ p_request,
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ verify_p_response_raw = context.get("p_response")
+ self.assertIsNotNone(verify_p_response_raw)
+ verify_bits = unpack_register_hex_unsigned(endian, verify_p_response_raw)
+
+ if verify_bits != 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 {:x}".format(reg_index, reg_info["name"], flipped_bits_int, verify_bits)
+ successful_writes -= 1
+ failed_writes +=1
+
+ return (successful_writes, failed_writes)
+
+ def is_bit_flippable_register(self, reg_info):
+ if not reg_info:
+ return False
+ if not "set" in reg_info:
+ return False
+ if reg_info["set"] != "General Purpose Registers":
+ return False
+ if ("container-regs" in reg_info) and (len(reg_info["container-regs"]) > 0):
+ # Don't try to bit flip registers contained in another register.
+ return False
+ if re.match("^.s$", reg_info["name"]):
+ # This is a 2-letter register name that ends in "s", like a segment register.
+ # Don't try to bit flip these.
+ return False
+ # Okay, this looks fine-enough.
+ return True
+
+ def read_register_values(self, reg_infos, endian, thread_id=None):
+ self.assertIsNotNone(reg_infos)
+ values = {}
+
+ for reg_info in reg_infos:
+ # We append a register index when load reg infos so we can work with subsets.
+ reg_index = reg_info.get("lldb_register_index")
+ self.assertIsNotNone(reg_index)
+
+ # Handle thread suffix.
+ if thread_id:
+ p_request = "read packet: $p{:x};thread:{:x}#00".format(reg_index, thread_id)
+ else:
+ p_request = "read packet: $p{:x}#00".format(reg_index)
+
+ # Read it with p.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines([
+ p_request,
+ { "direction":"send", "regex":r"^\$([0-9a-fA-F]+)#", "capture":{1:"p_response"} },
+ ], True)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Convert value from target endian to integral.
+ p_response = context.get("p_response")
+ self.assertIsNotNone(p_response)
+ self.assertTrue(len(p_response) > 0)
+ self.assertFalse(p_response[0] == "E")
+
+ values[reg_index] = unpack_register_hex_unsigned(endian, p_response)
+
+ return values \ No newline at end of file
OpenPOWER on IntegriCloud