Author: Charles Zablit Date: 2026-02-11T14:17:17Z New Revision: d7e5a7dacdb7c17e48a89e6e4fb50ccaa2fd5c94
URL: https://github.com/llvm/llvm-project/commit/d7e5a7dacdb7c17e48a89e6e4fb50ccaa2fd5c94 DIFF: https://github.com/llvm/llvm-project/commit/d7e5a7dacdb7c17e48a89e6e4fb50ccaa2fd5c94.diff LOG: [lldb-dap][windows] drain the ConPTY before attaching (#180578) Add a step to drain the init sequences emitted by the ConPTY before attaching it to the debuggee. A ConPTY (PseudoConsole) emits init sequences which flush the screen and contain the name of the program (ESC[2J for clear screen, ESC[H for cursor home and more). It's not desirable to filter them out: if a debuggee also emits them, lldb would filter that output as well. To work around this, the ConPTY is drained by attaching a dummy process to it, consuming the init sequences and then attaching the actual debuggee. --------- Co-authored-by: Nerixyz <[email protected]> Added: Modified: lldb/include/lldb/Host/windows/PseudoConsole.h lldb/source/Host/windows/PseudoConsole.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Host/windows/PseudoConsole.h b/lldb/include/lldb/Host/windows/PseudoConsole.h index a831c6028b252..996faf434585d 100644 --- a/lldb/include/lldb/Host/windows/PseudoConsole.h +++ b/lldb/include/lldb/Host/windows/PseudoConsole.h @@ -61,6 +61,16 @@ class PseudoConsole { /// invalid. HANDLE GetSTDINHandle() const { return m_conpty_input; }; + /// Drains initialization sequences from the ConPTY output pipe. + /// + /// When a process first attaches to a ConPTY, Windows emits VT100/ANSI escape + /// sequences (ESC[2J for clear screen, ESC[H for cursor home and more) as + /// part of the PseudoConsole initialization. To prevent these sequences from + /// appearing in the debugger output (and flushing lldb's shell for instance) + /// we launch a short-lived dummy process that triggers the initialization, + /// then drain all output before launching the actual debuggee. + llvm::Error DrainInitSequences(); + protected: HANDLE m_conpty_handle = ((HANDLE)(long long)-1); HANDLE m_conpty_output = ((HANDLE)(long long)-1); diff --git a/lldb/source/Host/windows/PseudoConsole.cpp b/lldb/source/Host/windows/PseudoConsole.cpp index b3314fd58bbb8..413c8a3328445 100644 --- a/lldb/source/Host/windows/PseudoConsole.cpp +++ b/lldb/source/Host/windows/PseudoConsole.cpp @@ -11,6 +11,7 @@ #include <mutex> #include "lldb/Host/windows/PipeWindows.h" +#include "lldb/Host/windows/ProcessLauncherWindows.h" #include "lldb/Host/windows/windows.h" #include "lldb/Utility/LLDBLog.h" @@ -118,6 +119,12 @@ llvm::Error PseudoConsole::OpenPseudoConsole() { m_conpty_output = hOutputRead; m_conpty_input = hInputWrite; + if (auto error = DrainInitSequences()) { + Log *log = GetLog(LLDBLog::Host); + LLDB_LOG_ERROR(log, std::move(error), + "failed to finalize ConPTY's setup: {0}"); + } + return llvm::Error::success(); } @@ -133,3 +140,62 @@ void PseudoConsole::Close() { m_conpty_input = INVALID_HANDLE_VALUE; m_conpty_output = INVALID_HANDLE_VALUE; } + +llvm::Error PseudoConsole::DrainInitSequences() { + STARTUPINFOEXW startupinfoex = {}; + startupinfoex.StartupInfo.cb = sizeof(STARTUPINFOEXW); + startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + + auto attributelist_or_err = ProcThreadAttributeList::Create(startupinfoex); + if (!attributelist_or_err) + return llvm::errorCodeToError(attributelist_or_err.getError()); + ProcThreadAttributeList attributelist = std::move(*attributelist_or_err); + if (auto error = attributelist.SetupPseudoConsole(m_conpty_handle)) + return error; + + PROCESS_INFORMATION pi = {}; + + wchar_t comspec[MAX_PATH]; + DWORD comspecLen = GetEnvironmentVariableW(L"COMSPEC", comspec, MAX_PATH); + if (comspecLen == 0 || comspecLen >= MAX_PATH) + return llvm::createStringError( + std::error_code(GetLastError(), std::system_category()), + "Failed to get the 'COMSPEC' environment variable"); + + std::wstring cmdline_str = std::wstring(comspec) + L" /c 'echo foo && exit'"; + std::vector<wchar_t> cmdline(cmdline_str.begin(), cmdline_str.end()); + cmdline.push_back(L'\0'); + + if (!CreateProcessW(/*lpApplicationName=*/comspec, cmdline.data(), + /*lpProcessAttributes=*/NULL, /*lpThreadAttributes=*/NULL, + /*bInheritHandles=*/TRUE, + /*dwCreationFlags=*/EXTENDED_STARTUPINFO_PRESENT | + CREATE_UNICODE_ENVIRONMENT, + /*lpEnvironment=*/NULL, /*lpCurrentDirectory=*/NULL, + /*lpStartupInfo=*/ + reinterpret_cast<STARTUPINFOW *>(&startupinfoex), + /*lpProcessInformation=*/&pi)) + return llvm::errorCodeToError( + std::error_code(GetLastError(), std::system_category())); + + char buf[4096]; + OVERLAPPED ov = {}; + ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + DWORD read; + ReadFile(m_conpty_output, buf, sizeof(buf), &read, &ov); + + WaitForSingleObject(pi.hProcess, INFINITE); + + if (GetOverlappedResult(m_conpty_output, &ov, &read, FALSE) && read > 0) { + ResetEvent(ov.hEvent); + ReadFile(m_conpty_output, buf, sizeof(buf), &read, &ov); + } + + CancelIo(m_conpty_output); + CloseHandle(ov.hEvent); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return llvm::Error::success(); +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
