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

Reply via email to