From c1c6cbaeea6b9f06ce15d7a5d5d1652ce801f9f4 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Thu, 31 Jul 2025 10:38:33 +0100 Subject: [PATCH 1/3] [windows][lldb] implement system logging on Windows (#150213) This patch makes LLDB use the Event Viewer on Windows (equivalent of system logging on Darwin) rather than piping to the standard output (which was deactivated in ca0a5247004b6d692978d10bdbf86e338133e60c. --- lldb/source/Host/common/Host.cpp | 27 ++++++++++--- lldb/source/Host/windows/Host.cpp | 63 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index fd5cc1d17da25..04380c6255f13 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -88,12 +88,27 @@ int __pthread_fchdir(int fildes); using namespace lldb; using namespace lldb_private; -#if !defined(__APPLE__) -// The system log is currently only meaningful on Darwin, where this means -// os_log. The meaning of a "system log" isn't as clear on other platforms, and -// therefore we don't providate a default implementation. Vendors are free to -// to implement this function if they have a use for it. -void Host::SystemLog(Severity severity, llvm::StringRef message) {} +#if !defined(__APPLE__) && !defined(_WIN32) +#include +void Host::SystemLog(Severity severity, llvm::StringRef message) { + static llvm::once_flag g_openlog_once; + llvm::call_once(g_openlog_once, [] { + openlog("lldb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER); + }); + int level = LOG_DEBUG; + switch (severity) { + case lldb::eSeverityInfo: + level = LOG_INFO; + break; + case lldb::eSeverityWarning: + level = LOG_WARNING; + break; + case lldb::eSeverityError: + level = LOG_ERR; + break; + } + syslog(level, "%s", message.data()); +} #endif #if !defined(__APPLE__) && !defined(_WIN32) diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index a7369e7eade3b..4e747f77afc0e 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -22,7 +22,9 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ManagedStatic.h" // Windows includes #include @@ -302,3 +304,64 @@ Environment Host::GetEnvironment() { } return env; } + +/// Manages the lifecycle of a Windows Event's Source. +/// The destructor will call DeregisterEventSource. +/// This class is meant to be used with \ref llvm::ManagedStatic. +class WindowsEventLog { +public: + WindowsEventLog() : handle(RegisterEventSource(nullptr, L"lldb")) {} + + ~WindowsEventLog() { + if (handle) + DeregisterEventSource(handle); + } + + HANDLE GetHandle() const { return handle; } + +private: + HANDLE handle; +}; + +static llvm::ManagedStatic event_log; + +static std::wstring AnsiToUtf16(const std::string &ansi) { + if (ansi.empty()) + return {}; + + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, nullptr, 0); + if (unicode_length == 0) + return {}; + + std::wstring unicode(unicode_length, L'\0'); + MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, &unicode[0], unicode_length); + return unicode; +} + +void Host::SystemLog(Severity severity, llvm::StringRef message) { + HANDLE h = event_log->GetHandle(); + if (!h) + return; + + std::wstring wide_message = AnsiToUtf16(message.str()); + if (wide_message.empty()) + return; + + LPCWSTR msg_ptr = wide_message.c_str(); + + WORD event_type; + switch (severity) { + case lldb::eSeverityWarning: + event_type = EVENTLOG_WARNING_TYPE; + break; + case lldb::eSeverityError: + event_type = EVENTLOG_ERROR_TYPE; + break; + case lldb::eSeverityInfo: + default: + event_type = EVENTLOG_INFORMATION_TYPE; + } + + ReportEventW(h, event_type, 0, 0, nullptr, 1, 0, &msg_ptr, nullptr); +} From d02ce92fa3fd6b48633da2905f1cb1543b1dcae5 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Wed, 20 Aug 2025 11:30:51 +0100 Subject: [PATCH 2/3] [lldb][windows] remove duplicate implementation of UTF8ToUTF16 (#154424) `std::wstring AnsiToUtf16(const std::string &ansi)` is a reimplementation of `llvm::sys::windows::UTF8ToUTF16`. This patch removes `AnsiToUtf16` and its usages entirely. --- lldb/source/Host/windows/Host.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 4e747f77afc0e..4277b8edb38e5 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -22,6 +22,7 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ManagedStatic.h" @@ -32,6 +33,8 @@ using namespace lldb; using namespace lldb_private; +using llvm::sys::windows::UTF8ToUTF16; + static bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple) { // Open the PE File as a binary file, and parse just enough information to @@ -325,31 +328,18 @@ class WindowsEventLog { static llvm::ManagedStatic event_log; -static std::wstring AnsiToUtf16(const std::string &ansi) { - if (ansi.empty()) - return {}; - - const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, nullptr, 0); - if (unicode_length == 0) - return {}; - - std::wstring unicode(unicode_length, L'\0'); - MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, &unicode[0], unicode_length); - return unicode; -} - void Host::SystemLog(Severity severity, llvm::StringRef message) { + if (message.empty()) + return; + HANDLE h = event_log->GetHandle(); if (!h) return; - std::wstring wide_message = AnsiToUtf16(message.str()); - if (wide_message.empty()) + llvm::SmallVector argsUTF16; + if (UTF8ToUTF16(message.str(), argsUTF16)) return; - LPCWSTR msg_ptr = wide_message.c_str(); - WORD event_type; switch (severity) { case lldb::eSeverityWarning: @@ -363,5 +353,7 @@ void Host::SystemLog(Severity severity, llvm::StringRef message) { event_type = EVENTLOG_INFORMATION_TYPE; } - ReportEventW(h, event_type, 0, 0, nullptr, 1, 0, &msg_ptr, nullptr); + LPCWSTR messages[1] = {argsUTF16.data()}; + ReportEventW(h, event_type, 0, 0, nullptr, std::size(messages), 0, messages, + nullptr); } From 50703859ec32d86b7574a71dbb605eeac67379ef Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Tue, 2 Sep 2025 18:06:15 +0100 Subject: [PATCH 3/3] [lldb][windows] use OutputDebugStringA instead of c to log events (#156474) In https://github.com/llvm/llvm-project/pull/150213 we made use of the Event Viewer on Windows (equivalent of system logging on Darwin) rather than piping to the standard output. This turned out to be too verbose in practice, as the Event Viewer is developer oriented and not user oriented. This patch swaps the use of `ReportEventW` for `OutputDebugStringA`, allowing to use tools such as `DebugView` to record logs when we are interested in receiving them, rather than continuously writing to the buffer. Please see an example below: Screenshot 2025-09-02 at 16 07 03 --- lldb/source/Host/windows/Host.cpp | 46 +++++++------------------------ 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 4277b8edb38e5..e8973a3fb937a 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -22,10 +22,8 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/ManagedStatic.h" // Windows includes #include @@ -308,52 +306,28 @@ Environment Host::GetEnvironment() { return env; } -/// Manages the lifecycle of a Windows Event's Source. -/// The destructor will call DeregisterEventSource. -/// This class is meant to be used with \ref llvm::ManagedStatic. -class WindowsEventLog { -public: - WindowsEventLog() : handle(RegisterEventSource(nullptr, L"lldb")) {} - - ~WindowsEventLog() { - if (handle) - DeregisterEventSource(handle); - } - - HANDLE GetHandle() const { return handle; } - -private: - HANDLE handle; -}; - -static llvm::ManagedStatic event_log; - void Host::SystemLog(Severity severity, llvm::StringRef message) { if (message.empty()) return; - HANDLE h = event_log->GetHandle(); - if (!h) - return; - - llvm::SmallVector argsUTF16; - if (UTF8ToUTF16(message.str(), argsUTF16)) - return; + std::string log_msg; + llvm::raw_string_ostream stream(log_msg); - WORD event_type; switch (severity) { case lldb::eSeverityWarning: - event_type = EVENTLOG_WARNING_TYPE; + stream << "[Warning] "; break; case lldb::eSeverityError: - event_type = EVENTLOG_ERROR_TYPE; + stream << "[Error] "; break; case lldb::eSeverityInfo: default: - event_type = EVENTLOG_INFORMATION_TYPE; + stream << "[Info] "; + break; } - LPCWSTR messages[1] = {argsUTF16.data()}; - ReportEventW(h, event_type, 0, 0, nullptr, std::size(messages), 0, messages, - nullptr); + stream << message; + stream.flush(); + + OutputDebugStringA(log_msg.c_str()); }