diff options
author | Todd Fiala <todd.fiala@gmail.com> | 2014-04-28 04:49:40 +0000 |
---|---|---|
committer | Todd Fiala <todd.fiala@gmail.com> | 2014-04-28 04:49:40 +0000 |
commit | a41d48cac8d29187a5b1421646ed1250e57be434 (patch) | |
tree | 126b73b4069a0e3186b28cedb7ba35369a227a28 | |
parent | e73658ddbb995c432db9ae171798102a5a42ffda (diff) | |
download | bcm5719-llvm-a41d48cac8d29187a5b1421646ed1250e57be434.tar.gz bcm5719-llvm-a41d48cac8d29187a5b1421646ed1250e57be434.zip |
Added two new test types: @debugserver_test and @llgs_test.
TestLldbGdbServer now supports both lldb-gdbserver (llgs) and
debugserver tests. Similar to the dsym/dwarf tests, they allow
running the same underlying gdb remote protocol tests against
lldb-gdbserver and debugserver. This will help make sure the
protocol-level tests for lldb-gdbserver faithfully represent
what debugserver does on OS X.
Switched back gdb remote protocol test logging to warning
and above (accidentally submitted it at debug level in a
recent commit).
llvm-svn: 207395
-rwxr-xr-x | lldb/test/dotest.py | 9 | ||||
-rw-r--r-- | lldb/test/lldbtest.py | 34 | ||||
-rw-r--r-- | lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py | 81 | ||||
-rw-r--r-- | lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py | 71 |
4 files changed, 157 insertions, 38 deletions
diff --git a/lldb/test/dotest.py b/lldb/test/dotest.py index 914cfc672d6..c80b3eba22c 100755 --- a/lldb/test/dotest.py +++ b/lldb/test/dotest.py @@ -126,6 +126,13 @@ just_do_benchmarks_test = False dont_do_dsym_test = "linux" in sys.platform or "freebsd" in sys.platform dont_do_dwarf_test = False +# Don't do debugserver tests on everything except OS X. +# Something for Windows here? +dont_do_debugserver_test = "linux" in sys.platform or "freebsd" in sys.platform + +# Don't do lldb-gdbserver (llgs) tests on anything except Linux. +dont_do_llgs_test = not ("linux" in sys.platform) + # The blacklist is optional (-b blacklistFile) and allows a central place to skip # testclass's and/or testclass.testmethod's. blacklist = None @@ -1300,6 +1307,8 @@ lldb.just_do_python_api_test = just_do_python_api_test lldb.just_do_benchmarks_test = just_do_benchmarks_test lldb.dont_do_dsym_test = dont_do_dsym_test lldb.dont_do_dwarf_test = dont_do_dwarf_test +lldb.dont_do_debugserver_test = dont_do_debugserver_test +lldb.dont_do_llgs_test = dont_do_llgs_test # Do we need to skip build and cleanup? lldb.skip_build_and_cleanup = skip_build_and_cleanup diff --git a/lldb/test/lldbtest.py b/lldb/test/lldbtest.py index 33feeedad24..f719f20cf5e 100644 --- a/lldb/test/lldbtest.py +++ b/lldb/test/lldbtest.py @@ -373,6 +373,40 @@ def dwarf_test(func): wrapper.__dwarf_test__ = True return wrapper +def debugserver_test(func): + """Decorate the item as a debugserver test.""" + if isinstance(func, type) and issubclass(func, unittest2.TestCase): + raise Exception("@debugserver_test can only be used to decorate a test method") + @wraps(func) + def wrapper(self, *args, **kwargs): + try: + if lldb.dont_do_debugserver_test: + self.skipTest("debugserver tests") + except AttributeError: + pass + return func(self, *args, **kwargs) + + # Mark this function as such to separate them from the regular tests. + wrapper.__debugserver_test__ = True + return wrapper + +def llgs_test(func): + """Decorate the item as a lldb-gdbserver test.""" + if isinstance(func, type) and issubclass(func, unittest2.TestCase): + raise Exception("@llgs_test can only be used to decorate a test method") + @wraps(func) + def wrapper(self, *args, **kwargs): + try: + if lldb.dont_do_llgs_test: + self.skipTest("llgs tests") + except AttributeError: + pass + return func(self, *args, **kwargs) + + # Mark this function as such to separate them from the regular tests. + wrapper.__llgs_test__ = True + return wrapper + def not_remote_testsuite_ready(func): """Decorate the item as a test which is not ready yet for remote testsuite.""" if isinstance(func, type) and issubclass(func, unittest2.TestCase): diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py index c05c3047411..c38c1a180cf 100644 --- a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py +++ b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py @@ -21,20 +21,27 @@ class LldbGdbServerTestCase(TestBase): _GDBREMOTE_KILL_PACKET = "$k#6b" - # _LOGGING_LEVEL = logging.WARNING - _LOGGING_LEVEL = logging.DEBUG + _LOGGING_LEVEL = logging.WARNING + # _LOGGING_LEVEL = logging.DEBUG def setUp(self): TestBase.setUp(self) - self.lldb_gdbserver_exe = get_lldb_gdbserver_exe() - if not self.lldb_gdbserver_exe: - self.skipTest("lldb_gdbserver exe not specified") FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s' logging.basicConfig(format=FORMAT) self.logger = logging.getLogger(__name__) self.logger.setLevel(self._LOGGING_LEVEL) + def init_llgs_test(self): + self.debug_monitor_exe = get_lldb_gdbserver_exe() + if not self.debug_monitor_exe: + self.skipTest("lldb_gdbserver exe not found") + + def init_debugserver_test(self): + self.debug_monitor_exe = get_debugserver_exe() + if not self.debug_monitor_exe: + self.skipTest("debugserver exe not found") + def create_socket(self): sock = socket.socket() logger = self.logger @@ -59,24 +66,24 @@ class LldbGdbServerTestCase(TestBase): def start_server(self): # start the server - server = pexpect.spawn("{} localhost:{}".format(self.lldb_gdbserver_exe, self.port)) + server = pexpect.spawn("{} localhost:{}".format(self.debug_monitor_exe, self.port)) # Turn on logging for what the child sends back. if self.TraceOn(): server.logfile_read = sys.stdout - # Schedule lldb-gdbserver to be shutting down during teardown. + # Schedule debug monitor to be shut down during teardown. logger = self.logger - def shutdown_lldb_gdbserver(): + def shutdown_debug_monitor(): try: server.close() except: logger.warning("failed to close pexpect server for debug monitor: {}; ignoring".format(sys.exc_info()[0])) - self.addTearDownHook(shutdown_lldb_gdbserver) + self.addTearDownHook(shutdown_debug_monitor) # Wait until we receive the server ready message before continuing. - server.expect_exact('Listening for a connection on localhost:{}'.format(self.port)) + server.expect_exact('Listening to port {} for a connection from localhost'.format(self.port)) # Create a socket to talk to the server self.sock = self.create_socket() @@ -91,11 +98,17 @@ class LldbGdbServerTestCase(TestBase): "lldb-gdbserver < 6> send packet: $OK#9a", "lldb-gdbserver < 1> read packet: +"] + @debugserver_test + def test_exe_starts_debugserver(self): + self.init_debugserver_test() + server = self.start_server() - def test_exe_starts(self): + @llgs_test + def test_exe_starts_llgs(self): + self.init_llgs_test() server = self.start_server() - def test_start_no_ack_mode(self): + def start_no_ack_mode(self): server = self.start_server() self.assertIsNotNone(server) @@ -104,8 +117,17 @@ class LldbGdbServerTestCase(TestBase): expect_lldb_gdbserver_replay(self, self.sock, log_lines, True, self._TIMEOUT_SECONDS, self.logger) - @unittest2.expectedFailure() - def test_thread_suffix_supported(self): + @debugserver_test + def test_start_no_ack_mode_debugserver(self): + self.init_debugserver_test() + self.start_no_ack_mode() + + @llgs_test + def test_start_no_ack_mode_llgs(self): + self.init_llgs_test() + self.start_no_ack_mode() + + def thread_suffix_supported(self): server = self.start_server() self.assertIsNotNone(server) @@ -117,8 +139,18 @@ class LldbGdbServerTestCase(TestBase): expect_lldb_gdbserver_replay(self, self.sock, log_lines, True, self._TIMEOUT_SECONDS, self.logger) + @debugserver_test + def test_thread_suffix_supported_debugserver(self): + self.init_debugserver_test() + self.thread_suffix_supported() + + @llgs_test @unittest2.expectedFailure() - def test_list_threads_in_stop_reply_supported(self): + def test_thread_suffix_supported_llgs(self): + self.init_llgs_test() + self.thread_suffix_supported() + + def list_threads_in_stop_reply_supported(self): server = self.start_server() self.assertIsNotNone(server) @@ -130,6 +162,17 @@ class LldbGdbServerTestCase(TestBase): expect_lldb_gdbserver_replay(self, self.sock, log_lines, True, self._TIMEOUT_SECONDS, self.logger) + @debugserver_test + def test_list_threads_in_stop_reply_supported_debugserver(self): + self.init_debugserver_test() + self.list_threads_in_stop_reply_supported() + + @llgs_test + @unittest2.expectedFailure() + def test_list_threads_in_stop_reply_supported_llgs(self): + self.init_llgs_test() + self.list_threads_in_stop_reply_supported() + def start_inferior(self): server = self.start_server() self.assertIsNotNone(server) @@ -148,13 +191,17 @@ class LldbGdbServerTestCase(TestBase): expect_lldb_gdbserver_replay(self, self.sock, log_lines, True, self._TIMEOUT_SECONDS, self.logger) + @debugserver_test @dsym_test - def test_start_inferior(self): + def test_start_inferior_debugserver_dsym(self): + self.init_debugserver_test() self.buildDsym() self.start_inferior() + @llgs_test @dwarf_test - def test_start_inferior(self): + def test_start_inferior_llgs_dwarf(self): + self.init_llgs_test() self.buildDwarf() self.start_inferior() diff --git a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py index b88dedcdb24..e91f82f1ce8 100644 --- a/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py +++ b/lldb/test/tools/lldb-gdbserver/lldbgdbserverutils.py @@ -7,36 +7,42 @@ import re import select import time -def _get_lldb_gdbserver_from_lldb(lldb_exe): - """Return the lldb-gdbserver exe path given the lldb exe path. - This method attempts to construct a valid lldb-gdbserver exe name +def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename): + """Return the debug monitor exe path given the lldb exe path. + + This method attempts to construct a valid debug monitor exe name from a given lldb exe name. It will return None if the synthesized - lldb-gdbserver name is not found to exist. + debug monitor name is not found to exist. - The lldb-gdbserver exe path is synthesized by taking the directory + The debug monitor exe path is synthesized by taking the directory of the lldb exe, and replacing the portion of the base name that - matches "lldb" (case insensitive) and replacing with "lldb-gdbserver". + matches "lldb" (case insensitive) and replacing with the value of + debug_monitor_basename. Args: lldb_exe: the path to an lldb executable. + debug_monitor_basename: the base name portion of the debug monitor + that will replace 'lldb'. + Returns: - A path to the lldb-gdbserver exe if it is found to exist; otherwise, + A path to the debug monitor exe if it is found to exist; otherwise, returns None. + """ exe_dir = os.path.dirname(lldb_exe) exe_base = os.path.basename(lldb_exe) # we'll rebuild the filename by replacing lldb with - # lldb-gdbserver, keeping any prefix or suffix in place. + # the debug monitor basename, keeping any prefix or suffix in place. regex = re.compile(r"lldb", re.IGNORECASE) - new_base = regex.sub("lldb-gdbserver", exe_base) + new_base = regex.sub(debug_monitor_basename, exe_base) - lldb_gdbserver_exe = os.path.join(exe_dir, new_base) - if os.path.exists(lldb_gdbserver_exe): - return lldb_gdbserver_exe + debug_monitor_exe = os.path.join(exe_dir, new_base) + if os.path.exists(debug_monitor_exe): + return debug_monitor_exe else: return None @@ -52,7 +58,20 @@ def get_lldb_gdbserver_exe(): if not lldb_exe: return None else: - return _get_lldb_gdbserver_from_lldb(lldb_exe) + return _get_debug_monitor_from_lldb(lldb_exe, "lldb-gedbserver") + +def get_debugserver_exe(): + """Return the debugserver exe path. + + Returns: + A path to the debugserver exe if it is found to exist; otherwise, + returns None. + """ + lldb_exe = os.environ["LLDB_EXEC"] + if not lldb_exe: + return None + else: + return _get_debug_monitor_from_lldb(lldb_exe, "debugserver") _LOG_LINE_REGEX = re.compile(r'^(lldb-gdbserver|debugserver)\s+<\s*(\d+)>' + @@ -87,8 +106,18 @@ def _is_packet_lldb_gdbserver_input(packet_type, llgs_input_is_read): raise "Unknown packet type: {}".format(packet_type) -_GDB_REMOTE_PACKET_REGEX = re.compile(r'^\$[^\#]*\#[0-9a-fA-F]{2}') +_STRIP_CHECKSUM_REGEX = re.compile(r'#[0-9a-fA-F]{2}$') + +def assert_packets_equal(asserter, actual_packet, expected_packet): + # strip off the checksum digits of the packet. When we're in + # no-ack mode, the # checksum is ignored, and should not be cause + # for a mismatched packet. + actual_stripped = _STRIP_CHECKSUM_REGEX.sub('', actual_packet) + expected_stripped = _STRIP_CHECKSUM_REGEX.sub('', expected_packet) + asserter.assertEqual(actual_stripped, expected_stripped) + +_GDB_REMOTE_PACKET_REGEX = re.compile(r'^\$([^\#]*)#[0-9a-fA-F]{2}') def expect_lldb_gdbserver_replay( asserter, @@ -134,19 +163,20 @@ def expect_lldb_gdbserver_replay( logger.debug("processing log line: {}".format(packet)) match = _LOG_LINE_REGEX.match(packet) if match: + playback_packet = match.group(4) if _is_packet_lldb_gdbserver_input( match.group(3), read_is_llgs_input): # handle as something to send to lldb-gdbserver on # socket. if logger: - logger.info("sending packet to llgs: {}".format(match.group(4))) - sock.sendall(match.group(4)) + logger.info("sending packet to llgs: {}".format(playback_packet)) + sock.sendall(playback_packet) else: # expect it as output from lldb-gdbserver received # from socket. if logger: - logger.info("receiving packet from llgs, should match: {}".format(match.group(4))) + logger.info("receiving packet from llgs, should match: {}".format(playback_packet)) start_time = time.time() timeout_time = start_time + timeout_seconds @@ -157,7 +187,7 @@ def expect_lldb_gdbserver_replay( if time.time() > timeout_time: raise Exception( 'timed out after {} seconds while waiting for llgs to respond with: {}, currently received: {}'.format( - timeout_seconds, match.group(4), receive_buffer)) + timeout_seconds, playback_packet, receive_buffer)) can_read, _, _ = select.select( [sock], [], [], 0) if can_read and sock in can_read: @@ -191,9 +221,8 @@ def expect_lldb_gdbserver_replay( # got a line - now try to match it against expected line if len(received_lines) > 0: - actual_receive = received_lines.pop(0) - expected_receive = match.group(4) - asserter.assertEqual(actual_receive, expected_receive) + received_packet = received_lines.pop(0) + assert_packets_equal(asserter, received_packet, playback_packet) return None |