alvinhochun created this revision. Herald added a project: All. alvinhochun added reviewers: mstorsjo, DavidSpickett, labath, omjavaid. alvinhochun added a comment. alvinhochun updated this revision to Diff 439961. alvinhochun updated this revision to Diff 441032. alvinhochun edited the summary of this revision. alvinhochun published this revision for review. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
WIP. To test this, first compile a test program (not needed if you already have programs that does OutputDebugString): #include <windows.h> int main() { OutputDebugStringW(L"Hello debug string"); return 0; } Debug the program in lldb. Before running the program, you need to run the command `log enable windows dbgprint`. When you run the program, you should see "DEBUG: Hello debug string" output in lldb. I think this should be enabled by default, but none of the logging categories for `LLDB_LOG` has default active. Is there a better way to do this? The log output can also get mixed with command output. alvinhochun added a comment. Add size check mstorsjo added a comment. For context - does gdb handle this too, and is it printed out to the gdb console? Did you test this both with and without lldb-server? (See `ShouldUseLLDBServer` in `ProcessWindows.cpp`.) alvinhochun added a comment. In D128541#3611052 <https://reviews.llvm.org/D128541#3611052>, @mstorsjo wrote: > For context - does gdb handle this too, and is it printed out to the gdb > console? Yes, gdb prints them to the console with a `warning: ` prefix. > Did you test this both with and without lldb-server? (See > `ShouldUseLLDBServer` in `ProcessWindows.cpp`.) It works without lldb-server. I tested lldb-server just now and found that none of the log output is printed -- I tried enabling all windows logging categories but got nothing. (I rebased the change onto 0aa6df65756d3ec7769e55424a41c7074849fe12 <https://reviews.llvm.org/rG0aa6df65756d3ec7769e55424a41c7074849fe12> before testing.) alvinhochun added a comment. Added test for Windows This implements handling of OUTPUT_DEBUG_STRING_EVENT which prints the debug strings using LLDB_LOG (channel "windows", category "dbgprint"). - TODO: see if there is a better way to output the debug strings... Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D128541 Files: lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h lldb/test/Shell/Process/Windows/outputdebugstring.cpp
Index: lldb/test/Shell/Process/Windows/outputdebugstring.cpp =================================================================== --- /dev/null +++ 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 <windows.h> + +int main(int argc, char *argv[]) { + OutputDebugStringW(L"Hello debug string\r\n"); + return 0; +} Index: lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.h +++ 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(); Index: lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp +++ 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<WindowsLog>() { return g_channel; Index: lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ 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; Index: lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ 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<char> str(static_cast<size_t>(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); Index: lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ 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: Index: lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ 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); Index: lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ 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 { Index: lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h +++ 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: Index: lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp +++ 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) { Index: lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h =================================================================== --- lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h +++ 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; }; } Index: lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ 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<lldb::addr_t>(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; }
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits