From: Todd Fiala Date: Fri, 27 Jun 2014 22:11:56 +0000 (+0000) Subject: Implemented gdb-remote protocol tests for vCont;s and vCont;s:{thread} X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e220200c854198b343c6e159e6c2a2f25c32136e;p=platform%2Fupstream%2Fllvm.git Implemented gdb-remote protocol tests for vCont;s and vCont;s:{thread} Also added tests for presence of vCont;c, vCont;C, vCont;s, vCont;S as returned by vCont? query. Broke out single step functionality from TestLldbGdbServer into base class. Used by new TestGdbRemoteSingleStep (using $s) and TestGdbRemote_vCont. Also part of llgs wrap-up, see: https://github.com/tfiala/lldb/issues/12 llvm-svn: 211965 --- diff --git a/lldb/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py b/lldb/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py new file mode 100644 index 0000000..2377ce1 --- /dev/null +++ b/lldb/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py @@ -0,0 +1,26 @@ +import unittest2 + +import gdbremote_testcase +from lldbtest import * + +class TestGdbRemoteSingleStep(gdbremote_testcase.GdbRemoteTestCaseBase): + + @debugserver_test + @dsym_test + def test_single_step_only_steps_one_instruction_with_s_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="s") + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_single_step_only_steps_one_instruction_with_s_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="s") + +if __name__ == '__main__': + unittest2.main() diff --git a/lldb/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py b/lldb/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py new file mode 100644 index 0000000..8f7d927 --- /dev/null +++ b/lldb/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py @@ -0,0 +1,134 @@ +import unittest2 + +import gdbremote_testcase +from lldbtest import * + +class TestGdbRemote_vCont(gdbremote_testcase.GdbRemoteTestCaseBase): + + def vCont_supports_mode(self, mode, inferior_args=None): + # Setup the stub and set the gdb remote command stream. + procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args) + self.add_vCont_query_packets() + + # Run the gdb remote command stream. + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Pull out supported modes. + supported_vCont_modes = self.parse_vCont_query_response(context) + self.assertIsNotNone(supported_vCont_modes) + + # Verify we support the given mode. + self.assertTrue(mode in supported_vCont_modes) + + def vCont_supports_c(self): + self.vCont_supports_mode("c") + + def vCont_supports_C(self): + self.vCont_supports_mode("C") + + def vCont_supports_s(self): + self.vCont_supports_mode("s") + + def vCont_supports_S(self): + self.vCont_supports_mode("S") + + @debugserver_test + @dsym_test + def test_vCont_supports_c_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.vCont_supports_c() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_vCont_supports_c_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.vCont_supports_c() + + @debugserver_test + @dsym_test + def test_vCont_supports_C_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.vCont_supports_C() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_vCont_supports_C_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.vCont_supports_C() + + @debugserver_test + @dsym_test + def test_vCont_supports_s_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.vCont_supports_s() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_vCont_supports_s_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.vCont_supports_s() + + @debugserver_test + @dsym_test + def test_vCont_supports_S_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.vCont_supports_S() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_vCont_supports_S_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.vCont_supports_S() + + @debugserver_test + @dsym_test + def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="vCont;s") + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=True, step_instruction="vCont;s") + + @debugserver_test + @dsym_test + def test_single_step_only_steps_one_instruction_with_vCont_s_thread_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}") + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_single_step_only_steps_one_instruction_with_vCont_s_thread_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}") + + + + +if __name__ == '__main__': + unittest2.main() diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py index 6aa1fe2..bcdc792 100644 --- a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py +++ b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py @@ -1418,166 +1418,6 @@ class LldbGdbServerTestCase(gdbremote_testcase.GdbRemoteTestCaseBase): 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() - def qSupported_returns_known_stub_features(self): # Start up the stub and start/prep the inferior. procs = self.prep_debug_monitor_and_inferior() diff --git a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py index de9b481..f48131e 100644 --- a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py +++ b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py @@ -6,6 +6,7 @@ import errno import unittest2 import pexpect import platform +import re import sets import signal import socket @@ -851,4 +852,175 @@ class GdbRemoteTestCaseBase(TestBase): values[reg_index] = unpack_register_hex_unsigned(endian, p_response) - return values \ No newline at end of file + return values + + def add_vCont_query_packets(self): + self.test_sequence.add_log_lines([ + "read packet: $vCont?#00", + {"direction":"send", "regex":r"^\$(vCont)?(.*)#[0-9a-fA-F]{2}$", "capture":{2:"vCont_query_response" } }, + ], True) + + def parse_vCont_query_response(self, context): + self.assertIsNotNone(context) + vCont_query_response = context.get("vCont_query_response") + + # Handle case of no vCont support at all - in which case the capture group will be none or zero length. + if not vCont_query_response or len(vCont_query_response) == 0: + return {} + + return {key:1 for key in vCont_query_response.split(";") if key and len(key) > 0} + + def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100, use_Hc_packet=True, step_instruction="s"): + """Used by single step test that appears in a few different contexts.""" + single_step_count = 0 + + while single_step_count < max_step_count: + self.assertIsNotNone(thread_id) + + # Build the packet for the single step instruction. We replace {thread}, if present, with the thread_id. + step_packet = "read packet: ${}#00".format(re.sub(r"{thread}", "{:x}".format(thread_id), step_instruction)) + # print "\nstep_packet created: {}\n".format(step_packet) + + # Single step. + self.reset_test_sequence() + if use_Hc_packet: + self.test_sequence.add_log_lines( + [# Set the continue thread. + "read packet: $Hc{0:x}#00".format(thread_id), + "send packet: $OK#00", + ], True) + self.test_sequence.add_log_lines([ + # Single step. + step_packet, + # "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 g_c1_c2_contents_are(self, args): + """Used by single step test that appears in a few different contexts.""" + 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 single_step_only_steps_one_instruction(self, use_Hc_packet=True, step_instruction="s"): + """Used by single step test that appears in a few different contexts.""" + # 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, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction) + 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, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction) + 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, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction) + 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, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction) + self.assertTrue(state_reached) + self.assertEquals(step_count, 1) diff --git a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py index 01ff2ce..72916f2 100644 --- a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py +++ b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py @@ -470,8 +470,8 @@ class GdbRemoteEntry(GdbRemoteEntryBase): # Handle captures. for group_index, var_name in self.capture.items(): capture_text = match.group(group_index) - if not capture_text: - raise Exception("No content for group index {}".format(group_index)) + # It is okay for capture text to be None - which it will be if it is a group that can match nothing. + # The user must be okay with it since the regex itself matched above. context[var_name] = capture_text if self.expect_captures: