Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -548,8 +548,13 @@ void ClearProcessSpecificData (); + // some stdio may be sent over gdb remote bool - ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const; + InferiorStdioOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const; + + // some output may be sent over gdb remote + bool + InferiorStdoutOrStderrOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const; //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -498,7 +498,32 @@ } bool -GDBRemoteCommunicationServer::ShouldRedirectInferiorOutputOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const +GDBRemoteCommunicationServer::InferiorStdioOverGdbRemote (const lldb_private::ProcessLaunchInfo &launch_info) const +{ + if (InferiorStdoutOrStderrOverGdbRemote(launch_info)) + { + // At least some stdio is going over gdb remote + return true; + } + + // else, check stdin + auto stdin_file_action = launch_info.GetFileActionForFD (STDIN_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 (stdin_file_action == nullptr) + { + // stdin may arrive over gdb-remote protocol. + return true; + } + + // no stdio over gdb remote + // it's either disabled, or redirected to a file + return false; +} + +bool +GDBRemoteCommunicationServer::InferiorStdoutOrStderrOverGdbRemote (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); @@ -506,15 +531,14 @@ // 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)) + 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. + // no stdout or stderr over gdb remote + // it's either disabled, or redirected to a file return false; } @@ -545,7 +569,7 @@ // 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)) + if (InferiorStdioOverGdbRemote (m_process_launch_info)) { if (log) log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); @@ -1179,8 +1203,11 @@ return error; } - m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); - m_stdio_communication.StartReadThread(); + if (InferiorStdoutOrStderrOverGdbRemote(m_process_launch_info)) + { + m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); + m_stdio_communication.StartReadThread(); + } return error; } @@ -1867,6 +1894,7 @@ FreePortForProcess(pid); return m_spawned_pids.erase(pid) > 0; } + bool GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton, lldb::pid_t pid, Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -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)