-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[DRAFT][lldb][windows] add Windows Virtual Console support #168729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[DRAFT][lldb][windows] add Windows Virtual Console support #168729
Conversation
|
@llvm/pr-subscribers-lldb Author: Charles Zablit (charles-zablit) ChangesPatch is 59.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/168729.diff 33 Files Affected:
diff --git a/lldb/include/lldb/Host/ProcessLaunchInfo.h b/lldb/include/lldb/Host/ProcessLaunchInfo.h
index 25762bc65295d..50a5af604ee26 100644
--- a/lldb/include/lldb/Host/ProcessLaunchInfo.h
+++ b/lldb/include/lldb/Host/ProcessLaunchInfo.h
@@ -118,7 +118,7 @@ class ProcessLaunchInfo : public ProcessInfo {
bool MonitorProcess() const;
- PseudoTerminal &GetPTY() { return *m_pty; }
+ std::shared_ptr<PseudoTerminal> GetPTY() const { return m_pty; }
void SetLaunchEventData(const char *data) { m_event_data.assign(data); }
diff --git a/lldb/include/lldb/Host/PseudoTerminal.h b/lldb/include/lldb/Host/PseudoTerminal.h
index bd1e2f56241b2..b61c213e138cb 100644
--- a/lldb/include/lldb/Host/PseudoTerminal.h
+++ b/lldb/include/lldb/Host/PseudoTerminal.h
@@ -35,11 +35,14 @@ class PseudoTerminal {
/// Destructor
///
- /// The destructor will close the primary and secondary file descriptors if
- /// they are valid and ownership has not been released using one of: @li
- /// PseudoTerminal::ReleasePrimaryFileDescriptor() @li
- /// PseudoTerminal::ReleaseSaveFileDescriptor()
- ~PseudoTerminal();
+ /// The destructor will close the primary and secondary file
+ /// descriptor/HANDLEs if they are valid and ownership has not been released
+ /// using PseudoTerminal::Close().
+ virtual ~PseudoTerminal();
+
+ /// Close all the file descriptors or Handles of the PseudoTerminal if they
+ /// are valid.
+ virtual void Close();
/// Close the primary file descriptor if it is valid.
void ClosePrimaryFileDescriptor();
@@ -59,8 +62,7 @@ class PseudoTerminal {
///
/// This class will close the file descriptors for the primary/secondary when
/// the destructor is called. The file handles can be released using either:
- /// @li PseudoTerminal::ReleasePrimaryFileDescriptor() @li
- /// PseudoTerminal::ReleaseSaveFileDescriptor()
+ /// @li PseudoTerminal::ReleasePrimaryFileDescriptor()
///
/// \return
/// \b Parent process: a child process ID that is greater
@@ -82,6 +84,16 @@ class PseudoTerminal {
/// \see PseudoTerminal::ReleasePrimaryFileDescriptor()
int GetPrimaryFileDescriptor() const;
+ /// The primary HANDLE accessor.
+ ///
+ /// This object retains ownership of the primary HANDLE when this
+ /// accessor is used.
+ ///
+ /// \return
+ /// The primary HANDLE, or INVALID_HANDLE_VALUE if the primary HANDLE is
+ /// not currently valid.
+ virtual void *GetPrimaryHandle() const { return ((void *)(long long)-1); };
+
/// The secondary file descriptor accessor.
///
/// This object retains ownership of the secondary file descriptor when this
@@ -105,7 +117,17 @@ class PseudoTerminal {
/// The name of the secondary pseudo terminal.
///
/// \see PseudoTerminal::OpenFirstAvailablePrimary()
- std::string GetSecondaryName() const;
+ virtual std::string GetSecondaryName() const;
+
+ /// The underlying Windows Pseudo Terminal HANDLE's accessor.
+ ///
+ /// This object retains ownership of the ConPTY's HANDLE when this
+ /// accessor is used.
+ ///
+ /// \return
+ /// The primary HANDLE, or INVALID_HANDLE_VALUE if the primary HANDLE is
+ /// not currently valid.
+ virtual void *GetPseudoTerminalHandle() { return ((void *)(long long)-1); };
/// Open the first available pseudo terminal.
///
@@ -126,7 +148,7 @@ class PseudoTerminal {
///
/// \see PseudoTerminal::GetPrimaryFileDescriptor() @see
/// PseudoTerminal::ReleasePrimaryFileDescriptor()
- llvm::Error OpenFirstAvailablePrimary(int oflag);
+ virtual llvm::Error OpenFirstAvailablePrimary(int oflag);
/// Open the secondary for the current primary pseudo terminal.
///
diff --git a/lldb/include/lldb/Host/windows/ConnectionPseudoTerminalWindows.h b/lldb/include/lldb/Host/windows/ConnectionPseudoTerminalWindows.h
new file mode 100644
index 0000000000000..6283312db7b8d
--- /dev/null
+++ b/lldb/include/lldb/Host/windows/ConnectionPseudoTerminalWindows.h
@@ -0,0 +1,61 @@
+//===-- ConnectionPseudoTerminalWindows.h ------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Host_windows_ConnectionPseudoConsoleWindows_h_
+#define liblldb_Host_windows_ConnectionPseudoConsoleWindows_h_
+
+#include "lldb/Host/windows/PseudoTerminalWindows.h"
+#include "lldb/Host/windows/windows.h"
+#include "lldb/Utility/Connection.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class ConnectionPseudoTerminal : public lldb_private::Connection {
+public:
+ ConnectionPseudoTerminal();
+
+ ConnectionPseudoTerminal(std::shared_ptr<PseudoTerminal> pty, bool owns_file);
+
+ ~ConnectionPseudoTerminal() override;
+
+ bool IsConnected() const override;
+
+ lldb::ConnectionStatus Connect(llvm::StringRef url,
+ Status *error_ptr) override;
+
+ lldb::ConnectionStatus Disconnect(Status *error_ptr) override;
+
+ size_t Read(void *dst, size_t dst_len, const Timeout<std::micro> &timeout,
+ lldb::ConnectionStatus &status, Status *error_ptr) override;
+
+ size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status,
+ Status *error_ptr) override;
+
+ std::string GetURI() override { return ""; };
+
+ bool InterruptRead() override;
+
+protected:
+ std::shared_ptr<PseudoTerminal> m_pty;
+ OVERLAPPED m_overlapped;
+ bool m_owns_file;
+ HANDLE m_event_handles[2];
+
+ enum { kBytesAvailableEvent, kInterruptEvent };
+
+private:
+ ConnectionPseudoTerminal(const ConnectionPseudoTerminal &) = delete;
+ const ConnectionPseudoTerminal &
+ operator=(const ConnectionPseudoTerminal &) = delete;
+};
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
index 81aea5b2022a5..a04077a5e1d03 100644
--- a/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
+++ b/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h
@@ -11,6 +11,9 @@
#include "lldb/Host/ProcessLauncher.h"
#include "lldb/Host/windows/windows.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/Environment.h"
+#include "llvm/Support/ErrorOr.h"
namespace lldb_private {
@@ -23,6 +26,32 @@ class ProcessLauncherWindows : public ProcessLauncher {
protected:
HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd);
+
+ /// Create a UTF-16 environment block to use with CreateProcessW.
+ ///
+ /// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
+ /// extra L'\0' (two bytes of 0). An empty environment must have one
+ /// empty string, followed by an extra L'\0'.
+ ///
+ /// The keys are sorted to comply with the CreateProcess' calling convention.
+ ///
+ /// Ensure that the resulting buffer is used in conjunction with
+ /// CreateProcessW and be sure that dwCreationFlags includes
+ /// CREATE_UNICODE_ENVIRONMENT.
+ ///
+ /// \param env The Environment object to convert.
+ /// \returns The sorted sequence of environment variables and their values,
+ /// separated by null terminators.
+ static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env);
+
+ /// Flattens an Args object into a Windows command-line wide string.
+ ///
+ /// Returns an empty string if args is empty.
+ ///
+ /// \param args The Args object to flatten.
+ /// \returns A wide string containing the flattened command line.
+ static llvm::ErrorOr<std::wstring>
+ GetFlattenedWindowsCommandStringW(Args args);
};
}
diff --git a/lldb/include/lldb/Host/windows/PseudoTerminalWindows.h b/lldb/include/lldb/Host/windows/PseudoTerminalWindows.h
new file mode 100644
index 0000000000000..8698ae2f8b804
--- /dev/null
+++ b/lldb/include/lldb/Host/windows/PseudoTerminalWindows.h
@@ -0,0 +1,37 @@
+//===-- PseudoTerminalWindows.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Host_Windows_PseudoTerminalWindows_H_
+#define liblldb_Host_Windows_PseudoTerminalWindows_H_
+
+#include "lldb/Host/PseudoTerminal.h"
+#include "lldb/Host/windows/windows.h"
+
+namespace lldb_private {
+
+class PseudoTerminalWindows : public PseudoTerminal {
+
+public:
+ void Close() override;
+
+ HPCON GetPseudoTerminalHandle() override { return m_conpty_handle; };
+
+ HANDLE GetPrimaryHandle() const override { return m_conpty_output; };
+
+ std::string GetSecondaryName() const override { return ""; };
+
+ llvm::Error OpenFirstAvailablePrimary(int oflag) override;
+
+protected:
+ HANDLE m_conpty_handle = INVALID_HANDLE_VALUE;
+ HANDLE m_conpty_output = INVALID_HANDLE_VALUE;
+ HANDLE m_conpty_input = INVALID_HANDLE_VALUE;
+};
+}; // namespace lldb_private
+
+#endif // liblldb_Host_Windows_PseudoTerminalWindows_H_
\ No newline at end of file
diff --git a/lldb/include/lldb/Host/windows/windows.h b/lldb/include/lldb/Host/windows/windows.h
index d53d4b9967268..2047e602291fc 100644
--- a/lldb/include/lldb/Host/windows/windows.h
+++ b/lldb/include/lldb/Host/windows/windows.h
@@ -9,9 +9,9 @@
#ifndef LLDB_lldb_windows_h_
#define LLDB_lldb_windows_h_
-#define NTDDI_VERSION NTDDI_VISTA
+// #define NTDDI_VERSION NTDDI_VISTA
#undef _WIN32_WINNT // undef a previous definition to avoid warning
-#define _WIN32_WINNT _WIN32_WINNT_VISTA
+// #define _WIN32_WINNT _WIN32_WINNT_VISTA
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#undef NOMINMAX // undef a previous definition to avoid warning
@@ -26,6 +26,7 @@
#undef near
#undef FAR
#undef NEAR
+#undef WIN32_MEMORY_INFORMATION_CLASS
#define FAR
#define NEAR
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index c1f9785e76f90..17a8ce713302a 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -2534,8 +2534,38 @@ void PruneThreadPlans();
void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
+ /// Associates a file descriptor with the process's STDIO handling
+ /// and configures an asynchronous reading of that descriptor.
+ ///
+ /// This method installs a ConnectionFileDescriptor for the passed file
+ /// descriptor and starts a dedicated read thread. If the read thread starts
+ /// successfully, the method also ensures that an IOHandlerProcessSTDIO is
+ /// created to manage user input to the process.
+ ///
+ /// The descriptor's ownership is transferred to the underlying
+ /// ConnectionFileDescriptor.
+ ///
+ /// \param[in] fd
+ /// The file descriptor to use for process STDIO communication. It's
+ /// assumed to be valid and will be managed by the newly created
+ /// connection.
+ ///
+ /// \see lldb_private::Process::STDIOReadThreadBytesReceived()
+ /// \see lldb_private::IOHandlerProcessSTDIO
+ /// \see lldb_private::ConnectionFileDescriptor
void SetSTDIOFileDescriptor(int file_descriptor);
+ /// Windows equivalent of Process::SetSTDIOFileDescriptor, with a
+ /// PseudoTerminalWindows instead of a file descriptor.
+ ///
+ /// \param pty
+ /// The PseudoTerminal to use for process STDIO communication. It is not
+ /// managed by the created read thread.
+ ///
+ /// \see lldb_private::ConnectionPseudoTerminalWindows
+ virtual void
+ SetPseudoTerminalHandle(const std::shared_ptr<PseudoTerminal> &pty) {};
+
// Add a permanent region of memory that should never be read or written to.
// This can be used to ensure that memory reads or writes to certain areas of
// memory never end up being sent to the DoReadMemory or DoWriteMemory
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index c9e8afe48fcde..1657dadf5ffe7 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -66,6 +66,7 @@ add_host_subdirectory(posix
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_host_subdirectory(windows
windows/ConnectionGenericFileWindows.cpp
+ windows/ConnectionPseudoTerminalWindows.cpp
windows/FileSystem.cpp
windows/Host.cpp
windows/HostInfoWindows.cpp
@@ -75,6 +76,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Windows")
windows/MainLoopWindows.cpp
windows/PipeWindows.cpp
windows/ProcessLauncherWindows.cpp
+ windows/PseudoTerminalWindows.cpp
windows/ProcessRunLock.cpp
)
else()
diff --git a/lldb/source/Host/common/ProcessLaunchInfo.cpp b/lldb/source/Host/common/ProcessLaunchInfo.cpp
index 49159cca9c57c..c3beef7031f18 100644
--- a/lldb/source/Host/common/ProcessLaunchInfo.cpp
+++ b/lldb/source/Host/common/ProcessLaunchInfo.cpp
@@ -20,7 +20,9 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FileSystem.h"
-#if !defined(_WIN32)
+#ifdef _WIN32
+#include "lldb/Host/windows/PseudoTerminalWindows.h"
+#else
#include <climits>
#endif
@@ -31,7 +33,12 @@ using namespace lldb_private;
ProcessLaunchInfo::ProcessLaunchInfo()
: ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),
- m_file_actions(), m_pty(new PseudoTerminal), m_monitor_callback(nullptr) {
+ m_file_actions(), m_monitor_callback(nullptr) {
+#ifdef _WIN32
+ m_pty = std::make_shared<PseudoTerminalWindows>();
+#else
+ m_pty = std::make_shared<PseudoTerminal>();
+#endif
}
ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
@@ -40,7 +47,13 @@ ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
const FileSpec &working_directory,
uint32_t launch_flags)
: ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),
- m_file_actions(), m_pty(new PseudoTerminal) {
+ m_file_actions() {
+#ifdef _WIN32
+ m_pty = std::make_shared<PseudoTerminalWindows>();
+#else
+ m_pty = std::make_shared<PseudoTerminal>();
+#endif
+
if (stdin_file_spec) {
FileAction file_action;
const bool read = true;
diff --git a/lldb/source/Host/common/PseudoTerminal.cpp b/lldb/source/Host/common/PseudoTerminal.cpp
index 53e91aff212a4..4d062c3618523 100644
--- a/lldb/source/Host/common/PseudoTerminal.cpp
+++ b/lldb/source/Host/common/PseudoTerminal.cpp
@@ -9,6 +9,7 @@
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/windows/windows.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Errno.h"
#include <cassert>
@@ -29,16 +30,11 @@
using namespace lldb_private;
-// PseudoTerminal constructor
PseudoTerminal::PseudoTerminal() = default;
-// Destructor
-//
-// The destructor will close the primary and secondary file descriptors if they
-// are valid and ownership has not been released using the
-// ReleasePrimaryFileDescriptor() or the ReleaseSaveFileDescriptor() member
-// functions.
-PseudoTerminal::~PseudoTerminal() {
+PseudoTerminal::~PseudoTerminal() { Close(); }
+
+void PseudoTerminal::Close() {
ClosePrimaryFileDescriptor();
CloseSecondaryFileDescriptor();
}
diff --git a/lldb/source/Host/windows/ConnectionPseudoTerminalWindows.cpp b/lldb/source/Host/windows/ConnectionPseudoTerminalWindows.cpp
new file mode 100644
index 0000000000000..b00fd745bc409
--- /dev/null
+++ b/lldb/source/Host/windows/ConnectionPseudoTerminalWindows.cpp
@@ -0,0 +1,191 @@
+//===-- ConnectionPseudoConsoleWindowsWindows.cpp
+//----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/windows/ConnectionPseudoTerminalWindows.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Timeout.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ReturnInfo {
+public:
+ void Set(size_t bytes, ConnectionStatus status, DWORD error_code) {
+ m_error = Status(error_code, eErrorTypeWin32);
+ m_bytes = bytes;
+ m_status = status;
+ }
+
+ void Set(size_t bytes, ConnectionStatus status, llvm::StringRef error_msg) {
+ m_error = Status::FromErrorString(error_msg.data());
+ m_bytes = bytes;
+ m_status = status;
+ }
+
+ size_t GetBytes() const { return m_bytes; }
+ ConnectionStatus GetStatus() const { return m_status; }
+ const Status &GetError() const { return m_error; }
+
+private:
+ Status m_error;
+ size_t m_bytes;
+ ConnectionStatus m_status;
+};
+
+ConnectionPseudoTerminal::ConnectionPseudoTerminal()
+ : m_pty(nullptr), m_owns_file(false) {
+ ::ZeroMemory(&m_overlapped, sizeof(m_overlapped));
+}
+
+ConnectionPseudoTerminal::ConnectionPseudoTerminal(
+ std::shared_ptr<PseudoTerminal> pty, bool owns_file)
+ : m_pty(pty), m_owns_file(owns_file) {
+ ::ZeroMemory(&m_overlapped, sizeof(m_overlapped));
+}
+
+ConnectionPseudoTerminal::~ConnectionPseudoTerminal() {}
+
+lldb::ConnectionStatus ConnectionPseudoTerminal::Connect(llvm::StringRef url,
+ Status *error_ptr) {
+ if (IsConnected())
+ return eConnectionStatusSuccess;
+ return eConnectionStatusNoConnection;
+}
+
+bool ConnectionPseudoTerminal::IsConnected() const {
+ return m_pty && (m_pty->GetPrimaryHandle() != INVALID_HANDLE_VALUE);
+}
+
+lldb::ConnectionStatus ConnectionPseudoTerminal::Disconnect(Status *error_ptr) {
+ Log *log = GetLog(LLDBLog::Connection);
+ LLDB_LOGF(log, "%p ConnectionPseudoTerminal::Disconnect ()",
+ static_cast<void *>(this));
+
+ if (!IsConnected())
+ return eConnectionStatusSuccess;
+
+ m_pty->Close();
+ return eConnectionStatusSuccess;
+}
+
+size_t ConnectionPseudoTerminal::Read(void *dst, size_t dst_len,
+ const Timeout<std::micro> &timeout,
+ lldb::ConnectionStatus &status,
+ Status *error_ptr) {
+ ReturnInfo return_info;
+ DWORD bytes_read = 0;
+ BOOL result = false;
+
+ if (error_ptr)
+ error_ptr->Clear();
+
+ HANDLE hInput = m_pty->GetPrimaryHandle();
+
+ if (!IsConnected()) {
+ return_info.Set(0, eConnectionStatusNoConnection, ERROR_INVALID_HANDLE);
+ goto finish;
+ }
+
+ // Setup OVERLAPPED event
+ m_overlapped.hEvent = m_event_handles[kBytesAvailableEvent];
+
+ result =
+ ::ReadFile(hInput, dst, static_cast<DWORD>(dst_len), NULL, &m_overlapped);
+ if (result || ::GetLastError() == ERROR_IO_PENDING) {
+ if (!result) {
+ // Operation pending: wait for completion or interrupt
+ DWORD milliseconds =
+ timeout ? static_cast<DWORD>(
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ *timeout)
+ .count())
+ : INFINITE;
+
+ DWORD wait_result = ::WaitForMultipleObjects(
+ static_cast<DWORD>(std::size(m_event_handles)), m_event_handles,
+ FALSE, milliseconds);
+
+ switch (wait_result) {
+ case WAIT_OBJECT_0 + kBytesAvailableEvent:
+ break; // Data ready
+ case WAIT_OBJECT_0 + kInterruptEvent:
+ return_info.Set(0, eConnectionStatusInterrupted, 0);
+ goto finish;
+ case WAIT_TIMEOUT:
+ return_info.Set(0, eConnectionStatusTimedOut, 0);
+ goto finish;
+ case WAIT_FAILED:
+ return_info.Set(0, eConnectionStatusError, ::GetLastError());
+ goto finish;
+ }
+ }
+
+ // Get actual number of bytes read
+ if (!::GetOverlappedResult(hInput, &m_overlapped, &bytes_read, FALSE)) {
+ DWORD err = ::GetLastError();
+ if (err == ERROR_HANDLE_EOF || err == ERROR_OPERATION_ABORTED ||
+ err == ERROR_BROKEN_PIPE)
+ return_info.Set(bytes_read, eConnectionStatusEndOfFile, 0);
+ ...
[truncated]
|
🐧 Linux x64 Test ResultsThe build failed before running any tests. Click on a failure below to see the details. tools/lldb/source/Host/CMakeFiles/lldbHost.dir/common/PseudoTerminal.cpp.oIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
This is still a DRAFT
This PR depends on: