18#include "llvm/Support/Errc.h"
19#include "llvm/Support/Errno.h"
24 HANDLE hOutput, DWORD dwFlags,
31 hModule = LoadLibraryW(L
"kernel32.dll");
33 llvm::Error err = llvm::errorCodeToError(
34 std::error_code(GetLastError(), std::system_category()));
36 "Could not load kernel32: {0}");
47 DWORD dwFlags,
HPCON *phPC) {
71 wchar_t pipe_name[MAX_PATH];
72 swprintf(pipe_name, MAX_PATH, L
"\\\\.\\pipe\\conpty-lldb-%d-%p",
73 GetCurrentProcessId(),
this);
75 CreateNamedPipeW(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
76 PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, NULL);
77 if (out_read == INVALID_HANDLE_VALUE)
78 return llvm::errorCodeToError(
79 std::error_code(GetLastError(), std::system_category()));
80 SECURITY_ATTRIBUTES write_sa = {
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
82 CreateFileW(pipe_name, GENERIC_WRITE, 0, inheritable ? &write_sa : NULL,
83 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
84 if (out_write == INVALID_HANDLE_VALUE) {
85 CloseHandle(out_read);
86 out_read = INVALID_HANDLE_VALUE;
87 return llvm::errorCodeToError(
88 std::error_code(GetLastError(), std::system_category()));
91 DWORD mode = PIPE_NOWAIT;
92 SetNamedPipeHandleState(out_read, &mode, NULL, NULL);
93 return llvm::Error::success();
104 "Attempted to open a PseudoConsole in a different mode than None");
107 return llvm::make_error<llvm::StringError>(
"ConPTY is not available",
108 llvm::errc::io_error);
111 "ConPTY has already been opened");
115 wchar_t pipe_name[MAX_PATH];
116 swprintf(pipe_name, MAX_PATH, L
"\\\\.\\pipe\\conpty-lldb-%d-%p",
117 GetCurrentProcessId(),
this);
118 HANDLE hOutputRead = INVALID_HANDLE_VALUE;
119 HANDLE hOutputWrite = INVALID_HANDLE_VALUE;
123 HANDLE hInputRead = INVALID_HANDLE_VALUE;
124 HANDLE hInputWrite = INVALID_HANDLE_VALUE;
125 if (!CreatePipe(&hInputRead, &hInputWrite, NULL, 0)) {
126 CloseHandle(hOutputRead);
127 CloseHandle(hOutputWrite);
128 return llvm::errorCodeToError(
129 std::error_code(GetLastError(), std::system_category()));
132 COORD consoleSize{80, 25};
133 CONSOLE_SCREEN_BUFFER_INFO csbi;
134 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
136 static_cast<SHORT
>(csbi.srWindow.Right - csbi.srWindow.Left + 1),
137 static_cast<SHORT
>(csbi.srWindow.Bottom - csbi.srWindow.Top + 1)};
138 HPCON hPC = INVALID_HANDLE_VALUE;
139 HRESULT hr =
kernel32.CreatePseudoConsole(consoleSize, hInputRead,
140 hOutputWrite, 0, &hPC);
141 CloseHandle(hInputRead);
142 CloseHandle(hOutputWrite);
145 CloseHandle(hInputWrite);
146 CloseHandle(hOutputRead);
147 return llvm::make_error<llvm::StringError>(
148 "Failed to create Windows ConPTY pseudo terminal",
149 llvm::errc::io_error);
160 "failed to finalize ConPTY's setup: {0}");
163 return llvm::Error::success();
177 std::unique_lock<std::mutex> guard(
m_mutex);
207 "Attempted to open a AnonymousPipes in a different mode than None");
209 SECURITY_ATTRIBUTES sa = {
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
210 HANDLE hStdinRead = INVALID_HANDLE_VALUE;
211 HANDLE hStdinWrite = INVALID_HANDLE_VALUE;
212 if (!CreatePipe(&hStdinRead, &hStdinWrite, &sa, 0))
213 return llvm::errorCodeToError(
214 std::error_code(GetLastError(), std::system_category()));
216 SetHandleInformation(hStdinWrite, HANDLE_FLAG_INHERIT, 0);
218 HANDLE hStdoutRead = INVALID_HANDLE_VALUE;
219 HANDLE hStdoutWrite = INVALID_HANDLE_VALUE;
221 CloseHandle(hStdinRead);
222 CloseHandle(hStdinWrite);
231 return llvm::Error::success();
235 STARTUPINFOEXW startupinfoex = {};
236 startupinfoex.StartupInfo.cb =
sizeof(STARTUPINFOEXW);
237 startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
240 if (!attributelist_or_err)
241 return llvm::errorCodeToError(attributelist_or_err.getError());
246 PROCESS_INFORMATION pi = {};
248 wchar_t comspec[MAX_PATH];
249 DWORD comspecLen = GetEnvironmentVariableW(L
"COMSPEC", comspec, MAX_PATH);
250 if (comspecLen == 0 || comspecLen >= MAX_PATH)
251 return llvm::createStringError(
252 std::error_code(GetLastError(), std::system_category()),
253 "Failed to get the 'COMSPEC' environment variable");
255 std::wstring cmdline_str = std::wstring(comspec) + L
" /c 'echo foo && exit'";
256 std::vector<wchar_t> cmdline(cmdline_str.begin(), cmdline_str.end());
257 cmdline.push_back(L
'\0');
259 if (!CreateProcessW(comspec, cmdline.data(),
262 EXTENDED_STARTUPINFO_PRESENT |
263 CREATE_UNICODE_ENVIRONMENT,
266 reinterpret_cast<STARTUPINFOW *
>(&startupinfoex),
268 return llvm::errorCodeToError(
269 std::error_code(GetLastError(), std::system_category()));
273 ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
278 WaitForSingleObject(pi.hProcess, INFINITE);
280 if (GetOverlappedResult(
m_conpty_output, &ov, &read, FALSE) && read > 0) {
281 ResetEvent(ov.hEvent);
286 CloseHandle(ov.hEvent);
287 CloseHandle(pi.hProcess);
288 CloseHandle(pi.hThread);
290 return llvm::Error::success();
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
HRESULT(WINAPI * CreatePseudoConsole_t)(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON *phPC)
VOID(WINAPI * ClosePseudoConsole_t)(HPCON hPC)
This class manages the lifetime of a PROC_THREAD_ATTRIBUTE_LIST, which is used with STARTUPINFOEX.
static llvm::ErrorOr< ProcThreadAttributeList > Create(STARTUPINFOEXW &startupinfoex)
Allocate memory for the attribute list, initialize it, and sets the lpAttributeList member of STARTUP...
llvm::Error SetupPseudoConsole(HPCON hPC)
Setup the PseudoConsole handle in the underlying LPPROC_THREAD_ATTRIBUTE_LIST.
llvm::Error OpenPseudoConsole()
Creates and opens a new ConPTY instance with a default console size of 80x25.
HANDLE m_pipe_child_stdin
llvm::Error CreateOverlappedPipePair(HANDLE &out_read, HANDLE &out_write, bool inheritable)
Creates a named pipe pair for overlapped I/O.
std::condition_variable m_cv
llvm::Error OpenAnonymousPipes()
Creates a pair of anonymous pipes to use for stdio instead of a ConPTY.
HANDLE m_pipe_child_stdout
void SetStopping(bool value)
Sets the stopping flag to value, signalling to threads waiting on the ConPTY that they should stop.
void Close()
Closes the ConPTY and invalidates its handle, without closing the STDIN and STDOUT pipes.
llvm::Error DrainInitSequences()
Drains initialization sequences from the ConPTY output pipe.
void ClosePseudoConsolePipes()
Closes the STDIN and STDOUT pipe handles and invalidates them.
bool IsConnected() const
Returns whether the ConPTY and its pipes are currently open and valid.
void CloseAnonymousPipes()
Closes the child-side pipe handles (stdin read end and stdout/stderr write end) that were passed to C...
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
VOID ClosePseudoConsole(HPCON hPC)
CreatePseudoConsole_t CreatePseudoConsole_
HRESULT CreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON *phPC)
ClosePseudoConsole_t ClosePseudoConsole_