Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -284,9 +284,6 @@ void ClearProcessSpecificData (); - bool - ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const; - void RegisterPacketHandlers (); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -223,11 +223,21 @@ return error; } - // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as needed. - // llgs local-process debugging may specify PTYs, which will eliminate the need to reflect inferior - // stdout/stderr over the gdb-remote protocol. - if (ShouldRedirectInferiorOutputOverGdbRemote (m_process_launch_info)) - { + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol + // as needed. + // llgs local-process debugging may specify PTY paths, which will make these + // file actions non-null + // process launch -i/e/o will also make these file actions non-null + // nullptr means that the traffic is expected to flow over gdb-remote protocol + if ( + m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr + ) + { + // nullptr means it's not redirected to file or pty (in case of LLGS local) + // at least one of stdio will be transferred pty<->gdb-remote + // we need to give the pty master handle to this object to read and/or write if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); @@ -269,27 +279,6 @@ return error; } -bool -GDBRemoteCommunicationServerLLGS::ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const -{ - // Retrieve the file actions specified for stdout and stderr. - auto stdout_file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); - auto stderr_file_action = launch_info.GetFileActionForFD (STDERR_FILENO); - - // If neither stdout and stderr file actions are specified, we're not doing anything special, so - // assume we want to redirect stdout/stderr over gdb-remote $O messages. - if ((stdout_file_action == nullptr) && (stderr_file_action == nullptr)) - { - // Send stdout/stderr over the gdb-remote protocol. - return true; - } - - // Any other setting for either stdout or stderr implies we are either suppressing - // it (with /dev/null) or we've got it set to a PTY. Either way, we don't want the - // output over gdb-remote. - return false; -} - lldb_private::Error GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) { @@ -831,8 +820,20 @@ return error; } - m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); - m_stdio_communication.StartReadThread(); + // llgs local-process debugging may specify PTY paths, which will make these + // file actions non-null + // process launch -e/o will also make these file actions non-null + // nullptr means that the traffic is expected to flow over gdb-remote protocol + if ( + m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr + ) + { + // output from the process must be forwarded over gdb-remote + // create a thread to read the handle and send the data + m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); + m_stdio_communication.StartReadThread(); + } return error; } Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -784,7 +784,7 @@ if (log) { if (stdin_path || stdout_path || stderr_path) - log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stdout=%s", + log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_path ? stdin_path : "", stdout_path ? stdout_path : "", @@ -856,7 +856,7 @@ stderr_path = slave_name; if (log) - log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stdout=%s", + log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_path ? stdin_path : "", stdout_path ? stdout_path : "", @@ -864,7 +864,7 @@ } if (log) - log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stdout=%s", + log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_path ? stdin_path : "", stdout_path ? stdout_path : "", Index: test/python_api/process/io/TestProcessIO.py =================================================================== --- test/python_api/process/io/TestProcessIO.py +++ test/python_api/process/io/TestProcessIO.py @@ -103,22 +103,30 @@ self.output_file = os.path.join(self.get_process_working_directory(), "output.txt") self.error_file = os.path.join(self.get_process_working_directory(), "error.txt") self.lines = ["Line 1", "Line 2", "Line 3"] - - def read_output_file_and_delete (self): - self.assertTrue(os.path.exists(self.output_file), "Make sure output.txt file exists") - f = open(self.output_file, 'r') + + # target_file - path on local file system or remote file system if running remote + # local_file - path on local system + def read_file_and_delete(self, target_file, local_file): + if lldb.remote_platform: + self.runCmd('platform get-file "{remote}" "{local}"'.format( + remote=target_file, local=local_file)) + + self.assertTrue(os.path.exists(local_file), 'Make sure "{local}" file exists'.format(local=local_file)) + f = open(local_file, 'r') contents = f.read() f.close() - os.unlink(self.output_file) + + #TODO: add 'platform delete-file' file command + #if lldb.remote_platform: + # self.runCmd('platform delete-file "{remote}"'.format(remote=target_file)) + os.unlink(local_file) return contents + def read_output_file_and_delete(self): + return self.read_file_and_delete(self.output_file, self.local_output_file) + def read_error_file_and_delete(self): - self.assertTrue(os.path.exists(self.error_file), "Make sure error.txt file exists") - f = open(self.error_file, 'r') - contents = f.read() - f.close() - os.unlink(self.error_file) - return contents + return self.read_file_and_delete(self.error_file, self.local_error_file) def create_target(self): '''Create the target and launch info that will be used by all tests''' @@ -145,10 +153,9 @@ # clean slate for the next test case. def cleanup(): os.unlink(self.local_input_file) - # if lldb.remote_platform: - # TODO: add delete file command - # self.runCmd('platform delete-file "{local}" "{remote}"'.format( - # local=self.local_input_file, remote=self.input_file))''' + #TODO: add 'platform delete-file' file command + #if lldb.remote_platform: + # self.runCmd('platform delete-file "{remote}"'.format(remote=self.input_file)) # Execute the cleanup function during test case tear down. self.addTearDownHook(cleanup)