From f3fbd1c0586ff6ec7895991e6c28f61a503c36a8 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 23 Jul 2016 20:50:09 +0000 Subject: Vendor import of lldb release_39 branch r276489: https://llvm.org/svn/llvm-project/lldb/branches/release_39@276489 --- .../test/tools/lldb-server/gdbremote_testcase.py | 155 +++++++++++++++------ 1 file changed, 114 insertions(+), 41 deletions(-) (limited to 'packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py') diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py index 113e01e36ba7a..d63ddbe399989 100644 --- a/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -24,14 +24,16 @@ from lldbsuite.test.lldbtest import * from lldbgdbserverutils import * import logging +class _ConnectionRefused(IOError): + pass + class GdbRemoteTestCaseBase(TestBase): - _TIMEOUT_SECONDS = 5 + NO_DEBUG_INFO_TESTCASE = True - _GDBREMOTE_KILL_PACKET = "$k#6b" + _TIMEOUT_SECONDS = 7 - _LOGGING_LEVEL = logging.WARNING - # _LOGGING_LEVEL = logging.DEBUG + _GDBREMOTE_KILL_PACKET = "$k#6b" # Start the inferior separately, attach to the inferior on the stub command line. _STARTUP_ATTACH = "attach" @@ -48,12 +50,44 @@ class GdbRemoteTestCaseBase(TestBase): TARGET_EXC_SOFTWARE = 0x95 TARGET_EXC_BREAKPOINT = 0x96 + _verbose_log_handler = None + _log_formatter = logging.Formatter(fmt='%(asctime)-15s %(levelname)-8s %(message)s') + + def setUpBaseLogging(self): + self.logger = logging.getLogger(__name__) + + if len(self.logger.handlers) > 0: + return # We have set up this handler already + + self.logger.propagate = False + self.logger.setLevel(logging.DEBUG) + + # log all warnings to stderr + handler = logging.StreamHandler() + handler.setLevel(logging.WARNING) + handler.setFormatter(self._log_formatter) + self.logger.addHandler(handler) + + + def isVerboseLoggingRequested(self): + # We will report our detailed logs if the user requested that the "gdb-remote" channel is + # logged. + return any(("gdb-remote" in channel) for channel in lldbtest_config.channels) + def setUp(self): TestBase.setUp(self) - FORMAT = '%(asctime)-15s %(levelname)-8s %(message)s' - logging.basicConfig(format=FORMAT) - self.logger = logging.getLogger(__name__) - self.logger.setLevel(self._LOGGING_LEVEL) + + self.setUpBaseLogging() + self.debug_monitor_extra_args = [] + self._pump_queues = socket_packet_pump.PumpQueues() + + if self.isVerboseLoggingRequested(): + # If requested, full logs go to a log file + self._verbose_log_handler = logging.FileHandler(self.log_basename + "-host.log") + self._verbose_log_handler.setFormatter(self._log_formatter) + self._verbose_log_handler.setLevel(logging.DEBUG) + self.logger.addHandler(self._verbose_log_handler) + self.test_sequence = GdbRemoteTestSequence(self.logger) self.set_inferior_startup_launch() self.port = self.get_next_port() @@ -76,6 +110,31 @@ class GdbRemoteTestCaseBase(TestBase): else: self.stub_hostname = "localhost" + def tearDown(self): + self._pump_queues.verify_queues_empty() + + self.logger.removeHandler(self._verbose_log_handler) + self._verbose_log_handler = None + TestBase.tearDown(self) + + def getLocalServerLogFile(self): + return self.log_basename + "-server.log" + + def setUpServerLogging(self, is_llgs): + if len(lldbtest_config.channels) == 0: + return # No logging requested + + if lldb.remote_platform: + log_file = lldbutil.join_remote_paths(lldb.remote_platform.GetWorkingDirectory(), "server.log") + else: + log_file = self.getLocalServerLogFile() + + if is_llgs: + self.debug_monitor_extra_args.append("--log-file=" + log_file) + self.debug_monitor_extra_args.append("--log-channels={}".format(":".join(lldbtest_config.channels))) + else: + self.debug_monitor_extra_args = ["--log-file=" + self.log_file, "--log-flags=0x800000"] + def get_next_port(self): return 12000 + random.randint(0,3999) @@ -147,30 +206,21 @@ class GdbRemoteTestCaseBase(TestBase): return stub_port - def run_shell_cmd(self, cmd): - platform = self.dbg.GetSelectedPlatform() - shell_cmd = lldb.SBPlatformShellCommand(cmd) - err = platform.Run(shell_cmd) - if err.Fail() or shell_cmd.GetStatus(): - m = "remote_platform.RunShellCommand('%s') failed:\n" % cmd - m += ">>> return code: %d\n" % shell_cmd.GetStatus() - if err.Fail(): - m += ">>> %s\n" % str(err).strip() - m += ">>> %s\n" % (shell_cmd.GetOutput() or - "Command generated no output.") - raise Exception(m) - return shell_cmd.GetOutput().strip() - def init_llgs_test(self, use_named_pipe=True): if lldb.remote_platform: # Remote platforms don't support named pipe based port negotiation use_named_pipe = False # Grab the ppid from /proc/[shell pid]/stat - shell_stat = self.run_shell_cmd("cat /proc/$$/stat") + err, retcode, shell_stat = self.run_platform_command("cat /proc/$$/stat") + self.assertTrue(err.Success() and retcode == 0, + "Failed to read file /proc/$$/stat: %s, retcode: %d" % (err.GetCString(), retcode)) + # [pid] ([executable]) [state] [*ppid*] pid = re.match(r"^\d+ \(.+\) . (\d+)", shell_stat).group(1) - ls_output = self.run_shell_cmd("ls -l /proc/%s/exe" % pid) + err, retcode, ls_output = self.run_platform_command("ls -l /proc/%s/exe" % pid) + self.assertTrue(err.Success() and retcode == 0, + "Failed to read file /proc/%s/exe: %s, retcode: %d" % (pid, err.GetCString(), retcode)) exe = ls_output.split()[-1] # If the binary has been deleted, the link name has " (deleted)" appended. @@ -182,10 +232,7 @@ class GdbRemoteTestCaseBase(TestBase): self.skipTest("lldb-server exe not found") self.debug_monitor_extra_args = ["gdbserver"] - - if len(lldbtest_config.channels) > 0: - self.debug_monitor_extra_args.append("--log-file={}-server.log".format(self.log_basename)) - self.debug_monitor_extra_args.append("--log-channels={}".format(":".join(lldbtest_config.channels))) + self.setUpServerLogging(is_llgs=True) if use_named_pipe: (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe() @@ -194,7 +241,7 @@ class GdbRemoteTestCaseBase(TestBase): self.debug_monitor_exe = get_debugserver_exe() if not self.debug_monitor_exe: self.skipTest("debugserver exe not found") - self.debug_monitor_extra_args = ["--log-file={}-server.log".format(self.log_basename), "--log-flags=0x800000"] + self.setUpServerLogging(is_llgs=False) if use_named_pipe: (self.named_pipe_path, self.named_pipe, self.named_pipe_fd) = self.create_named_pipe() # The debugserver stub has a race on handling the 'k' command, so it sends an X09 right away, then sends the real X notification @@ -209,6 +256,22 @@ class GdbRemoteTestCaseBase(TestBase): subprocess.call(adb + [ "tcp:%d" % source, "tcp:%d" % target]) self.addTearDownHook(remove_port_forward) + def _verify_socket(self, sock): + # Normally, when the remote stub is not ready, we will get ECONNREFUSED during the + # connect() attempt. However, due to the way how ADB forwarding works, on android targets + # the connect() will always be successful, but the connection will be immediately dropped + # if ADB could not connect on the remote side. This function tries to detect this + # situation, and report it as "connection refused" so that the upper layers attempt the + # connection again. + triple = self.dbg.GetSelectedPlatform().GetTriple() + if not re.match(".*-.*-.*-android", triple): + return # Not android. + can_read, _, _ = select.select([sock], [], [], 0.1) + if sock not in can_read: + return # Data is not available, but the connection is alive. + if len(sock.recv(1, socket.MSG_PEEK)) == 0: + raise _ConnectionRefused() # Got EOF, connection dropped. + def create_socket(self): sock = socket.socket() logger = self.logger @@ -217,8 +280,14 @@ class GdbRemoteTestCaseBase(TestBase): if re.match(".*-.*-.*-android", triple): self.forward_adb_port(self.port, self.port, "forward", self.stub_device) + logger.info("Connecting to debug monitor on %s:%d", self.stub_hostname, self.port) connect_info = (self.stub_hostname, self.port) - sock.connect(connect_info) + try: + sock.connect(connect_info) + except socket.error as serr: + if serr.errno == errno.ECONNREFUSED: + raise _ConnectionRefused() + raise serr def shutdown_socket(): if sock: @@ -235,6 +304,8 @@ class GdbRemoteTestCaseBase(TestBase): self.addTearDownHook(shutdown_socket) + self._verify_socket(sock) + return sock def set_inferior_startup_launch(self): @@ -258,12 +329,6 @@ class GdbRemoteTestCaseBase(TestBase): commandline_args += ["--named-pipe", self.named_pipe_path] return commandline_args - def run_platform_command(self, cmd): - platform = self.dbg.GetSelectedPlatform() - shell_command = lldb.SBPlatformShellCommand(cmd) - err = platform.Run(shell_command) - return (err, shell_command.GetOutput()) - def launch_debug_monitor(self, attach_pid=None, logfile=None): # Create the command line. commandline_args = self.get_debug_monitor_command_line_args(attach_pid=attach_pid) @@ -322,12 +387,12 @@ class GdbRemoteTestCaseBase(TestBase): while connect_attemps < MAX_CONNECT_ATTEMPTS: # Create a socket to talk to the server try: + logger.info("Connect attempt %d", connect_attemps+1) self.sock = self.create_socket() return server - except socket.error as serr: - # We're only trying to handle connection refused. - if serr.errno != errno.ECONNREFUSED: - raise serr + except _ConnectionRefused as serr: + # Ignore, and try again. + pass time.sleep(0.5) connect_attemps += 1 @@ -546,7 +611,8 @@ class GdbRemoteTestCaseBase(TestBase): def expect_gdbremote_sequence(self, timeout_seconds=None): if not timeout_seconds: timeout_seconds = self._TIMEOUT_SECONDS - return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, timeout_seconds, self.logger) + return expect_lldb_gdbserver_replay(self, self.sock, self.test_sequence, + self._pump_queues, timeout_seconds, self.logger) _KNOWN_REGINFO_KEYS = [ "name", @@ -556,6 +622,7 @@ class GdbRemoteTestCaseBase(TestBase): "encoding", "format", "set", + "gcc", "ehframe", "dwarf", "generic", @@ -1281,6 +1348,9 @@ class GdbRemoteTestCaseBase(TestBase): #MIPS required "3" (ADDIU, SB, LD) machine instructions for updation of variable value if re.match("mips",arch): expected_step_count = 3 + #S390X requires "2" (LARL, MVI) machine instructions for updation of variable value + if re.match("s390x",arch): + expected_step_count = 2 self.assertEqual(step_count, expected_step_count) # Verify we hit the next state. @@ -1297,3 +1367,6 @@ class GdbRemoteTestCaseBase(TestBase): self.assertTrue(state_reached) self.assertEqual(step_count, expected_step_count) + def maybe_strict_output_regex(self, regex): + return '.*'+regex+'.*' if lldbplatformutil.hasChattyStderr(self) else '^'+regex+'$' + -- cgit v1.2.3