forked from OSchip/llvm-project
Add support for SBProcess::PutSTDIN to remote processes
Processes running on a remote target can already send $O messages to send stdout but there is no way to send stdin to a remote inferior. This allows processes using the API to pump stdin into a remote inferior process. It fixes a hang in TestProcessIO.py when running against a remote target. llvm-svn: 228419
This commit is contained in:
parent
7206d7a5d2
commit
e0be425a53
|
@ -3180,6 +3180,7 @@ protected:
|
|||
lldb::IOHandlerSP m_process_input_reader;
|
||||
Communication m_stdio_communication;
|
||||
Mutex m_stdio_communication_mutex;
|
||||
bool m_stdio_disable; /// Remember process launch setting
|
||||
std::string m_stdout_data;
|
||||
std::string m_stderr_data;
|
||||
Mutex m_profile_data_comm_mutex;
|
||||
|
|
|
@ -1866,6 +1866,21 @@ GDBRemoteCommunicationClient::SendAttach
|
|||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SendStdinNotification (const char* data, size_t data_len)
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutCString("I");
|
||||
packet.PutBytesAsRawHex8(data, data_len);
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return response.GetError();
|
||||
|
||||
}
|
||||
|
||||
const lldb_private::ArchSpec &
|
||||
GDBRemoteCommunicationClient::GetHostArchitecture ()
|
||||
{
|
||||
|
|
|
@ -174,6 +174,23 @@ public:
|
|||
StringExtractorGDBRemote& response);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a GDB remote protocol 'I' packet that delivers stdin
|
||||
/// data to the remote process.
|
||||
///
|
||||
/// @param[in] data
|
||||
/// A pointer to stdin data.
|
||||
///
|
||||
/// @param[in] data_len
|
||||
/// The number of bytes available at \a data.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the attach was successful, or an error indicating
|
||||
/// an error code.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendStdinNotification(const char* data, size_t data_len);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the path to use for stdin/out/err for a process
|
||||
/// that will be launched with the 'A' packet.
|
||||
|
|
|
@ -370,6 +370,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
|
|||
packet_result = Handle_H (packet);
|
||||
break;
|
||||
|
||||
case StringExtractorGDBRemote::eServerPacketType_I:
|
||||
packet_result = Handle_I (packet);
|
||||
break;
|
||||
|
||||
case StringExtractorGDBRemote::eServerPacketType_m:
|
||||
packet_result = Handle_m (packet);
|
||||
break;
|
||||
|
@ -3429,6 +3433,46 @@ GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet)
|
|||
return SendOKResponse();
|
||||
}
|
||||
|
||||
GDBRemoteCommunicationServer::PacketResult
|
||||
GDBRemoteCommunicationServer::Handle_I (StringExtractorGDBRemote &packet)
|
||||
{
|
||||
Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
|
||||
|
||||
// Ensure we're llgs.
|
||||
if (!IsGdbServer())
|
||||
return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_I() unimplemented");
|
||||
|
||||
// Fail if we don't have a current process.
|
||||
if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
|
||||
return SendErrorResponse (0x15);
|
||||
}
|
||||
|
||||
packet.SetFilePos (::strlen("I"));
|
||||
char tmp[4096];
|
||||
for (;;)
|
||||
{
|
||||
size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp));
|
||||
if (read == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// write directly to stdin *this might block if stdin buffer is full*
|
||||
// TODO: enqueue this block in circular buffer and send window size to remote host
|
||||
ConnectionStatus status;
|
||||
Error error;
|
||||
m_stdio_communication.Write(tmp, read, status, &error);
|
||||
if (error.Fail())
|
||||
{
|
||||
return SendErrorResponse (0x15);
|
||||
}
|
||||
}
|
||||
|
||||
return SendOKResponse();
|
||||
}
|
||||
|
||||
GDBRemoteCommunicationServer::PacketResult
|
||||
GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet)
|
||||
{
|
||||
|
|
|
@ -414,6 +414,9 @@ protected:
|
|||
PacketResult
|
||||
Handle_H (StringExtractorGDBRemote &packet);
|
||||
|
||||
PacketResult
|
||||
Handle_I (StringExtractorGDBRemote &packet);
|
||||
|
||||
PacketResult
|
||||
Handle_interrupt (StringExtractorGDBRemote &packet);
|
||||
|
||||
|
|
|
@ -942,6 +942,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
|
|||
|
||||
SetPrivateState (SetThreadStopInfo (m_last_stop_packet));
|
||||
|
||||
m_stdio_disable = disable_stdio;
|
||||
if (!disable_stdio)
|
||||
{
|
||||
if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
|
||||
|
@ -2477,6 +2478,10 @@ ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
|
|||
ConnectionStatus status;
|
||||
m_stdio_communication.Write(src, src_len, status, NULL);
|
||||
}
|
||||
else if (!m_stdio_disable)
|
||||
{
|
||||
m_gdb_comm.SendStdinNotification(src, src_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -720,6 +720,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
|
|||
m_process_input_reader (),
|
||||
m_stdio_communication ("process.stdio"),
|
||||
m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_stdio_disable(true),
|
||||
m_stdout_data (),
|
||||
m_stderr_data (),
|
||||
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
|
||||
|
@ -3911,6 +3912,7 @@ Process::Destroy ()
|
|||
}
|
||||
m_stdio_communication.StopReadThread();
|
||||
m_stdio_communication.Disconnect();
|
||||
m_stdio_disable = true;
|
||||
|
||||
if (m_process_input_reader)
|
||||
{
|
||||
|
|
|
@ -265,6 +265,9 @@ StringExtractorGDBRemote::GetServerPacketType () const
|
|||
case 'H':
|
||||
return eServerPacketType_H;
|
||||
|
||||
case 'I':
|
||||
return eServerPacketType_I;
|
||||
|
||||
case 'k':
|
||||
if (packet_size == 1) return eServerPacketType_k;
|
||||
break;
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
eServerPacketType_g,
|
||||
eServerPacketType_G,
|
||||
eServerPacketType_H,
|
||||
eServerPacketType_I, // stdin notification
|
||||
eServerPacketType_k,
|
||||
eServerPacketType_m,
|
||||
eServerPacketType_M,
|
||||
|
|
Loading…
Reference in New Issue