diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -235,6 +235,8 @@ LLDB_LOGV(log, "Entering WaitForDebugEvent loop"); while (should_debug) { LLDB_LOGV(log, "Calling WaitForDebugEvent"); + // TODO: GetProcAddress("WaitForDebugEventEx") and call it if available to + // opt in to receiving Unicode messages from OutputDebugString. BOOL wait_result = WaitForDebugEvent(&dbe, INFINITE); if (wait_result) { DWORD continue_status = DBG_CONTINUE; @@ -533,6 +535,16 @@ DWORD DebuggerThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id) { + Log *log = GetLog(WindowsLog::Event); + lldb::addr_t debug_string_addr = + reinterpret_cast(info.lpDebugStringData); + LLDB_LOG(log, + "process {0} thread {1} OutputDebugString (data={2:x}, unicode={3}, " + "len={4})", + m_process.GetProcessId(), thread_id, debug_string_addr, + info.fUnicode, info.nDebugStringLength); + m_debug_delegate->OnDebugString(debug_string_addr, info.fUnicode, + info.nDebugStringLength); return DBG_CONTINUE; } diff --git a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h --- a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h @@ -35,7 +35,8 @@ virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) = 0; virtual void OnUnloadDll(lldb::addr_t module_addr) = 0; - virtual void OnDebugString(const std::string &string) = 0; + virtual void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word) = 0; virtual void OnDebuggerError(const Status &error, uint32_t type) = 0; }; } diff --git a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h @@ -51,7 +51,8 @@ void OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr) override; void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &message) override; + void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word) override; void OnDebuggerError(const Status &error, uint32_t type) override; private: diff --git a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp @@ -56,9 +56,11 @@ process->OnUnloadDll(module_addr); } -void LocalDebugDelegate::OnDebugString(const std::string &string) { +void LocalDebugDelegate::OnDebugString(lldb::addr_t debug_string_addr, + bool is_unicode, + uint16_t length_lower_word) { if (ProcessWindowsSP process = GetProcessPointer()) - process->OnDebugString(string); + process->OnDebugString(debug_string_addr, is_unicode, length_lower_word); } void LocalDebugDelegate::OnDebuggerError(const Status &error, uint32_t type) { diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -172,8 +172,9 @@ m_process.OnUnloadDll(module_addr); } - void OnDebugString(const std::string &string) override { - m_process.OnDebugString(string); + void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word) override { + m_process.OnDebugString(debug_string_addr, is_unicode, length_lower_word); } void OnDebuggerError(const Status &error, uint32_t type) override { diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h @@ -59,7 +59,8 @@ virtual void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr); virtual void OnUnloadDll(lldb::addr_t module_addr); - virtual void OnDebugString(const std::string &string); + virtual void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word); virtual void OnDebuggerError(const Status &error, uint32_t type); protected: diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp @@ -530,7 +530,9 @@ // Do nothing by default } -void ProcessDebugger::OnDebugString(const std::string &string) {} +void ProcessDebugger::OnDebugString(lldb::addr_t debug_string_addr, + bool is_unicode, + uint16_t length_lower_word) {} void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) { llvm::sys::ScopedLock lock(m_mutex); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -95,7 +95,8 @@ void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) override; void OnUnloadDll(lldb::addr_t module_addr) override; - void OnDebugString(const std::string &string) override; + void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word) override; void OnDebuggerError(const Status &error, uint32_t type) override; Status GetWatchpointSupportInfo(uint32_t &num) override; diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -810,7 +810,33 @@ dyld->OnUnloadModule(module_addr); } -void ProcessWindows::OnDebugString(const std::string &string) {} +void ProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, + bool is_unicode, + uint16_t length_lower_word) { + Log *log = GetLog(WindowsLog::DbgPrint); + // TODO: Support Unicode debug string: Unicode debug strings are supplied + // only if WaitForDebugEventEx was called instead of WaitForDebugEvent. + if (!is_unicode) { + std::vector str(static_cast(length_lower_word)); + Status error; + size_t bytes_read = DoReadMemory(debug_string_addr, str.data(), + str.size() * sizeof(char), error); + if (bytes_read == str.size() * sizeof(char)) { + llvm::StringRef str_ref(str.data(), str.size()); + // The string should contain a trailing NUL terminator. Remove it because + // it interferes with consume_back. + if (!str_ref.empty() && str_ref.back() == '\0') + str_ref = str_ref.drop_back(); + // Remove one trailing newline because LLDB_LOG also adds one. + if (!str_ref.empty() && str_ref.back() == '\n') + str_ref = str_ref.drop_back(); + if (!str_ref.empty() && str_ref.back() == '\r') + str_ref = str_ref.drop_back(); + if (!str_ref.empty()) + LLDB_LOG(log, "DEBUG: {0}", str_ref); + } + } +} void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) { llvm::sys::ScopedLock lock(m_mutex); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h @@ -23,7 +23,8 @@ Registers = Log::ChannelFlag<5>, // Log register operations Step = Log::ChannelFlag<6>, // Log step operations Thread = Log::ChannelFlag<7>, // Log thread operations - LLVM_MARK_AS_BITMASK_ENUM(Thread) + DbgPrint = Log::ChannelFlag<8>, // Log OutputDebugString messages + LLVM_MARK_AS_BITMASK_ENUM(DbgPrint) }; LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp @@ -19,9 +19,11 @@ {{"registers"}, {"log register read/writes"}, WindowsLog::Registers}, {{"step"}, {"log step related activities"}, WindowsLog::Step}, {{"thread"}, {"log thread events and activities"}, WindowsLog::Thread}, + {{"dbgprint"}, {"log OutputDebugString messages"}, WindowsLog::DbgPrint}, }; -static Log::Channel g_channel(g_categories, WindowsLog::Process); +static Log::Channel g_channel(g_categories, + WindowsLog::Process | WindowsLog::DbgPrint); template <> Log::Channel &lldb_private::LogChannelFor() { return g_channel; diff --git a/lldb/test/Shell/Process/Windows/outputdebugstring.cpp b/lldb/test/Shell/Process/Windows/outputdebugstring.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Process/Windows/outputdebugstring.cpp @@ -0,0 +1,14 @@ +// clang-format off + +// REQUIRES: system-windows +// RUN: %clangxx_host -o %t.exe -lntdll -- %s +// RUN: %lldb -f %t.exe -o "log enable windows dbgprint" -o "run" | FileCheck %s + +// CHECK: DEBUG: Hello debug string + +#include + +int main(int argc, char *argv[]) { + OutputDebugStringW(L"Hello debug string\r\n"); + return 0; +}