[Lldb-commits] [lldb] r210481 - Added gdb-remote test for s packet, single stepping.
Todd Fiala
todd.fiala at gmail.com
Mon Jun 9 10:46:37 PDT 2014
Author: tfiala
Date: Mon Jun 9 12:46:37 2014
New Revision: 210481
URL: http://llvm.org/viewvc/llvm-project?rev=210481&view=rev
Log:
Added gdb-remote test for s packet, single stepping.
Modified:
lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
lldb/trunk/test/tools/lldb-gdbserver/main.cpp
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=210481&r1=210480&r2=210481&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Mon Jun 9 12:46:37 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"breakpoint", self._testMethodName):
+ # if not re.search(r"(single_step|break)", self._testMethodName):
# self.skipTest("focusing on one test")
def reset_test_sequence(self):
@@ -372,6 +372,30 @@ class LldbGdbServerTestCase(TestBase):
return threads
+ def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
+ self.test_sequence.add_log_lines(
+ [# Set the breakpoint.
+ "read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
+ # Verify the stub could set it.
+ "send packet: $OK#00",
+ ], True)
+
+ if (do_continue):
+ self.test_sequence.add_log_lines(
+ [# Continue the inferior.
+ "read packet: $c#00",
+ # Expect a breakpoint stop report.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+ ], True)
+
+ def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
+ self.test_sequence.add_log_lines(
+ [# Remove the breakpoint.
+ "read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
+ # Verify the stub could unset it.
+ "send packet: $OK#00",
+ ], True)
+
def run_process_then_stop(self, run_seconds=1):
# Tell the stub to continue.
self.test_sequence.add_log_lines(
@@ -1010,8 +1034,8 @@ class LldbGdbServerTestCase(TestBase):
self.add_threadinfo_collection_packets()
self.test_sequence.add_log_lines(
["read packet: $qC#00",
- { "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }],
- True)
+ { "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }
+ ], True)
# Run the packet stream.
context = self.expect_gdbremote_sequence()
@@ -1310,7 +1334,7 @@ class LldbGdbServerTestCase(TestBase):
# Start up the inferior.
procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-message-address-hex:", "sleep:5"])
+ inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-data-address-hex:g_message", "sleep:5"])
# Run the process
self.test_sequence.add_log_lines(
@@ -1319,7 +1343,7 @@ class LldbGdbServerTestCase(TestBase):
"read packet: $c#00",
# Match output line that prints the memory address of the message buffer within the inferior.
# Note we require launch-only testing so we can get inferior otuput.
- { "type":"output_match", "regex":r"^message address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"message_address"} },
+ { "type":"output_match", "regex":r"^data address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"message_address"} },
# Now stop the inferior.
"read packet: {}".format(chr(03)),
# And wait for the stop notification.
@@ -1616,26 +1640,15 @@ class LldbGdbServerTestCase(TestBase):
self.assertIsNotNone(pc_lldb_reg_index)
self.assertIsNotNone(pc_reg_info)
- # Grab the address.
+ # Grab the function address.
self.assertIsNotNone(context.get("function_address"))
function_address = int(context.get("function_address"), 16)
# Set the breakpoint.
# Note this might need to be switched per platform (ARM, mips, etc.).
BREAKPOINT_KIND = 1
-
self.reset_test_sequence()
- self.test_sequence.add_log_lines(
- [
- # Set the breakpoint.
- "read packet: $Z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
- # Verify the stub could set it.
- "send packet: $OK#00",
- # Continue the inferior.
- "read packet: $c#00",
- # Expect a breakpoint stop report.
- {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
- ], True)
+ self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
# Run the packet stream.
context = self.expect_gdbremote_sequence()
@@ -1709,6 +1722,166 @@ class LldbGdbServerTestCase(TestBase):
self.set_inferior_startup_launch()
self.software_breakpoint_set_and_remove_work()
+ def g_c1_c2_contents_are(self, args):
+ g_c1_address = args["g_c1_address"]
+ g_c2_address = args["g_c2_address"]
+ expected_g_c1 = args["expected_g_c1"]
+ expected_g_c2 = args["expected_g_c2"]
+
+ # Read g_c1 and g_c2 contents.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ ["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
+ "read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
+ {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Check if what we read from inferior memory is what we are expecting.
+ self.assertIsNotNone(context.get("g_c1_contents"))
+ self.assertIsNotNone(context.get("g_c2_contents"))
+
+ return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
+
+ def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100):
+ single_step_count = 0
+
+ while single_step_count < max_step_count:
+ # Single step.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [# Set the continue thread.
+ "read packet: $Hc{0:x}#00".format(thread_id),
+ "send packet: $OK#00",
+ # Single step.
+ "read packet: $s#00",
+ # "read packet: $vCont;s:{0:x}#00".format(thread_id),
+ # Expect a breakpoint stop report.
+ {"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)
+ self.assertIsNotNone(context.get("stop_signo"))
+ self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
+
+ single_step_count += 1
+
+ # See if the predicate is true. If so, we're done.
+ if predicate(args):
+ return (True, single_step_count)
+
+ # The predicate didn't return true within the runaway step count.
+ return (False, single_step_count)
+
+ def single_step_only_steps_one_instruction(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:swap_chars", "get-data-address-hex:g_c1", "get-data-address-hex:g_c2", "sleep:1", "call-function:swap_chars", "sleep:5"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [# Start running after initial stop.
+ "read packet: $c#00",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$",
+ "capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(03)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the main thread id.
+ self.assertIsNotNone(context.get("stop_thread_id"))
+ main_thread_id = int(context.get("stop_thread_id"), 16)
+
+ # Grab the function address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Grab the data addresses.
+ self.assertIsNotNone(context.get("g_c1_address"))
+ g_c1_address = int(context.get("g_c1_address"), 16)
+
+ self.assertIsNotNone(context.get("g_c2_address"))
+ g_c2_address = int(context.get("g_c2_address"), 16)
+
+ # Set a breakpoint at the given address.
+ # Note this might need to be switched per platform (ARM, mips, etc.).
+ BREAKPOINT_KIND = 1
+ self.reset_test_sequence()
+ self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Remove the breakpoint.
+ self.reset_test_sequence()
+ self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify g_c1 and g_c2 match expected initial state.
+ args = {}
+ args["g_c1_address"] = g_c1_address
+ args["g_c2_address"] = g_c2_address
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "1"
+
+ self.assertTrue(self.g_c1_c2_contents_are(args))
+
+ # Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
+ args["expected_g_c1"] = "1"
+ args["expected_g_c2"] = "1"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=25)
+ self.assertTrue(state_reached)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "1"
+ args["expected_g_c2"] = "0"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
+ self.assertTrue(state_reached)
+ self.assertEquals(step_count, 1)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "0"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
+ self.assertTrue(state_reached)
+ self.assertEquals(step_count, 1)
+
+ # Verify we hit the next state.
+ args["expected_g_c1"] = "0"
+ args["expected_g_c2"] = "1"
+ (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
+ self.assertTrue(state_reached)
+ self.assertEquals(step_count, 1)
+
+ @debugserver_test
+ @dsym_test
+ def test_single_step_only_steps_one_instruction_debugserver_dsym(self):
+ self.init_debugserver_test()
+ self.buildDsym()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction()
+
+ @llgs_test
+ @dwarf_test
+ @unittest2.expectedFailure()
+ def test_single_step_only_steps_one_instruction_llgs_dwarf(self):
+ self.init_llgs_test()
+ self.buildDwarf()
+ self.set_inferior_startup_launch()
+ self.single_step_only_steps_one_instruction()
+
if __name__ == '__main__':
unittest2.main()
Modified: lldb/trunk/test/tools/lldb-gdbserver/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/main.cpp?rev=210481&r1=210480&r2=210481&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Mon Jun 9 12:46:37 2014
@@ -24,7 +24,7 @@ static const char *const RETVAL_PREFIX
static const char *const SLEEP_PREFIX = "sleep:";
static const char *const STDERR_PREFIX = "stderr:";
static const char *const SET_MESSAGE_PREFIX = "set-message:";
-static const char *const GET_MESSAGE_ADDRESS_COMMAND = "get-message-address-hex:";
+static const char *const GET_DATA_ADDRESS_PREFIX = "get-data-address-hex:";
static const char *const GET_STACK_ADDRESS_COMMAND = "get-stack-address-hex:";
static const char *const GET_HEAP_ADDRESS_COMMAND = "get-heap-address-hex:";
@@ -46,6 +46,9 @@ static bool g_is_segfaulting = false;
static char g_message[256];
+static volatile char g_c1 = '0';
+static volatile char g_c2 = '1';
+
static void
print_thread_id ()
{
@@ -114,6 +117,16 @@ signal_handler (int signo)
}
static void
+swap_chars ()
+{
+ g_c1 = '1';
+ g_c2 = '0';
+
+ g_c1 = '0';
+ g_c2 = '1';
+}
+
+static void
hello ()
{
pthread_mutex_lock (&g_print_mutex);
@@ -251,10 +264,19 @@ int main (int argc, char **argv)
g_message[sizeof (g_message) - 1] = '\0';
}
- else if (std::strstr (argv[i], GET_MESSAGE_ADDRESS_COMMAND))
+ else if (std::strstr (argv[i], GET_DATA_ADDRESS_PREFIX))
{
+ volatile void *data_p = nullptr;
+
+ if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_message"))
+ data_p = &g_message[0];
+ else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c1"))
+ data_p = &g_c1;
+ else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c2"))
+ data_p = &g_c2;
+
pthread_mutex_lock (&g_print_mutex);
- printf ("message address: %p\n", &g_message[0]);
+ printf ("data address: %p\n", data_p);
pthread_mutex_unlock (&g_print_mutex);
}
else if (std::strstr (argv[i], GET_HEAP_ADDRESS_COMMAND))
@@ -275,11 +297,12 @@ int main (int argc, char **argv)
}
else if (std::strstr (argv[i], GET_CODE_ADDRESS_PREFIX))
{
- // Defaut to providing the address of main.
void (*func_p)() = nullptr;
if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "hello"))
func_p = hello;
+ else if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "swap_chars"))
+ func_p = swap_chars;
pthread_mutex_lock (&g_print_mutex);
printf ("code address: %p\n", func_p);
@@ -290,6 +313,8 @@ int main (int argc, char **argv)
// Defaut to providing the address of main.
if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "hello") == 0)
hello();
+ else if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "swap_chars") == 0)
+ swap_chars();
else
{
pthread_mutex_lock (&g_print_mutex);
More information about the lldb-commits
mailing list