LLDB mainline
PseudoConsole.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include <mutex>
12
16
17#include "llvm/Support/Errc.h"
18#include "llvm/Support/Errno.h"
19
20using namespace lldb_private;
21
22typedef HRESULT(WINAPI *CreatePseudoConsole_t)(COORD size, HANDLE hInput,
23 HANDLE hOutput, DWORD dwFlags,
24 HPCON *phPC);
25
26typedef VOID(WINAPI *ClosePseudoConsole_t)(HPCON hPC);
27
28struct Kernel32 {
30 hModule = LoadLibraryW(L"kernel32.dll");
31 if (!hModule) {
32 llvm::Error err = llvm::errorCodeToError(
33 std::error_code(GetLastError(), std::system_category()));
34 LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(err),
35 "Could not load kernel32: {0}");
36 return;
37 }
39 (CreatePseudoConsole_t)GetProcAddress(hModule, "CreatePseudoConsole");
41 (ClosePseudoConsole_t)GetProcAddress(hModule, "ClosePseudoConsole");
43 }
44
45 HRESULT CreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput,
46 DWORD dwFlags, HPCON *phPC) {
47 assert(CreatePseudoConsole_ && "CreatePseudoConsole is not available!");
48 return CreatePseudoConsole_(size, hInput, hOutput, dwFlags, phPC);
49 }
50
52 assert(ClosePseudoConsole_ && "ClosePseudoConsole is not available!");
53 return ClosePseudoConsole_(hPC);
54 }
55
56 bool IsConPTYAvailable() { return isAvailable; }
57
58private:
59 HMODULE hModule;
63};
64
66
68
70 if (!kernel32.IsConPTYAvailable())
71 return llvm::make_error<llvm::StringError>("ConPTY is not available",
72 llvm::errc::io_error);
73
74 // close any previously opened handles
75 Close();
76
77 HRESULT hr;
78 HANDLE hInputRead = INVALID_HANDLE_VALUE;
79 HANDLE hInputWrite = INVALID_HANDLE_VALUE;
80 HANDLE hOutputRead = INVALID_HANDLE_VALUE;
81 HANDLE hOutputWrite = INVALID_HANDLE_VALUE;
82
83 wchar_t pipe_name[MAX_PATH];
84 swprintf(pipe_name, MAX_PATH, L"\\\\.\\pipe\\conpty-lldb-%d-%p",
85 GetCurrentProcessId(), this);
86
87 // A 4096 bytes buffer should be large enough for the majority of console
88 // burst outputs.
89 hOutputRead =
90 CreateNamedPipeW(pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
91 PIPE_TYPE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, NULL);
92 hOutputWrite = CreateFileW(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
93 FILE_ATTRIBUTE_NORMAL, NULL);
94
95 if (!CreatePipe(&hInputRead, &hInputWrite, NULL, 0))
96 return llvm::errorCodeToError(
97 std::error_code(GetLastError(), std::system_category()));
98
99 COORD consoleSize{80, 25};
100 HPCON hPC = INVALID_HANDLE_VALUE;
101 hr = kernel32.CreatePseudoConsole(consoleSize, hInputRead, hOutputWrite, 0,
102 &hPC);
103 CloseHandle(hInputRead);
104 CloseHandle(hOutputWrite);
105
106 if (FAILED(hr)) {
107 CloseHandle(hInputWrite);
108 CloseHandle(hOutputRead);
109 return llvm::make_error<llvm::StringError>(
110 "Failed to create Windows ConPTY pseudo terminal",
111 llvm::errc::io_error);
112 }
113
114 DWORD mode = PIPE_NOWAIT;
115 SetNamedPipeHandleState(hOutputRead, &mode, NULL, NULL);
116
117 m_conpty_handle = hPC;
118 m_conpty_output = hOutputRead;
119 m_conpty_input = hInputWrite;
120
121 return llvm::Error::success();
122}
123
125 if (m_conpty_handle != INVALID_HANDLE_VALUE)
126 kernel32.ClosePseudoConsole(m_conpty_handle);
127 if (m_conpty_input != INVALID_HANDLE_VALUE)
128 CloseHandle(m_conpty_input);
129 if (m_conpty_output != INVALID_HANDLE_VALUE)
130 CloseHandle(m_conpty_output);
131
132 m_conpty_handle = INVALID_HANDLE_VALUE;
133 m_conpty_input = INVALID_HANDLE_VALUE;
134 m_conpty_output = INVALID_HANDLE_VALUE;
135}
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
HRESULT(WINAPI * CreatePseudoConsole_t)(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON *phPC)
VOID(WINAPI * ClosePseudoConsole_t)(HPCON hPC)
static Kernel32 kernel32
void * HPCON
void * HANDLE
void Close()
Close the ConPTY, its read/write handles and invalidate them.
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.
Definition Log.h:332
VOID ClosePseudoConsole(HPCON hPC)
CreatePseudoConsole_t CreatePseudoConsole_
HMODULE hModule
bool IsConPTYAvailable()
HRESULT CreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON *phPC)
ClosePseudoConsole_t ClosePseudoConsole_