Author: Charles Zablit Date: 2026-06-12T17:47:35+02:00 New Revision: 5906827e155cc5fca10cd505b88a4e21b861d65b
URL: https://github.com/llvm/llvm-project/commit/5906827e155cc5fca10cd505b88a4e21b861d65b DIFF: https://github.com/llvm/llvm-project/commit/5906827e155cc5fca10cd505b88a4e21b861d65b.diff LOG: [lldb][Windows] Forward OUTPUT_DEBUG_STRING_EVENT through lldb-server (#203546) Hoist `ReadDebugString` into `ProcessDebugger` so both plugins share it, then add `NativeProcessWindows::OnDebugString` that reads the string, converts UTF-16 to UTF-8 when needed, and delivers via `NativeDelegate::NewProcessOutput`. Fixes `Process/Windows/output_debug_string.cpp` on Windows under `LLDB_USE_LLDB_SERVER=1`. Added: Modified: lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp 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 Removed: ################################################################################ diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index f0e88e78e6136..889a2e743c07f 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -713,6 +713,44 @@ void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { m_pending_library_events = true; } +void NativeProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, + bool is_unicode, + uint16_t length_lower_word) { + Log *log = GetLog(WindowsLog::Process); + + llvm::SmallVector<char, 256> buffer; + if (llvm::Error err = ProcessDebugger::ReadDebugString( + debug_string_addr, is_unicode, length_lower_word, buffer)) { + std::string err_str = llvm::toString(std::move(err)); + std::string msg = + llvm::formatv("Failed to read debug string at {0:x} " + "(size & 0xffff={1}, unicode={2}): {3}\n", + debug_string_addr, length_lower_word, is_unicode, err_str) + .str(); + LLDB_LOG(log, "{0}", msg); + m_delegate.NewProcessOutput(this, llvm::StringRef(msg)); + return; + } + if (buffer.empty()) + return; + + if (is_unicode) { + assert(buffer.size() % 2 == 0); + llvm::ArrayRef<unsigned short> utf16( + reinterpret_cast<const unsigned short *>(buffer.data()), + buffer.size() / 2); + std::string out; + if (!llvm::convertUTF16ToUTF8String(utf16, out)) { + LLDB_LOG(log, "Debug string is not valid Utf 16"); + return; + } + m_delegate.NewProcessOutput(this, llvm::StringRef(out.data(), out.size())); + } else { + m_delegate.NewProcessOutput(this, + llvm::StringRef(buffer.data(), buffer.size())); + } +} + llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessWindows::Manager::Launch( ProcessLaunchInfo &launch_info, diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index d1c57fc01e06b..e2879bcd803fe 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -124,6 +124,8 @@ class NativeProcessWindows : public NativeProcessProtocol, void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) override; void OnUnloadDll(lldb::addr_t module_addr) override; + void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word) override; protected: NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp index 5a2c3bdc87d47..84c74bb1ba919 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp @@ -555,6 +555,57 @@ void ProcessDebugger::OnDebugString(lldb::addr_t debug_string_addr, // Do nothing by default } +llvm::Error +ProcessDebugger::ReadDebugString(lldb::addr_t debug_string_addr, + bool is_unicode, uint16_t length_lower_word, + llvm::SmallVectorImpl<char> &output) { + if (is_unicode && length_lower_word % 2 != 0) + return llvm::createStringError( + "Utf16 string can't have uneven size in bytes"); + + const auto is_zero_terminated = [&] { + // The zero terminator is always at the end of the buffer. + if (is_unicode) + return output.size() >= 2 && output.back() == 0 && + output[output.size() - 2] == 0; + + return !output.empty() && output.back() == 0; + }; + + // Read at most 1 MiB ((1 << 16) * 16 - 1 Bytes) since we don't know the exact + // size of the string. We know that `strlen(string) & 0xffff == + // length_lower_word`, so we read in chunks until we reach the terminator: + // - 0: `length_lower_word` Bytes + // - 1..16: 64 KiB (= 2^16 Bytes) + size_t start = length_lower_word == 0 ? 1 : 0; + for (size_t i = start; i < 16; ++i) { + output.resize_for_overwrite(length_lower_word + i * (1 << 16)); + size_t chunk_size = i == 0 ? length_lower_word : (1 << 16); + lldb::addr_t addr = debug_string_addr + output.size_in_bytes() - chunk_size; + + size_t bytes_read = 0; + Status error = + ReadMemory(addr, output.end() - chunk_size, chunk_size, bytes_read); + if (error.Fail()) + return error.takeError(); + + if (bytes_read != chunk_size) { + return llvm::createStringErrorV( + "Expected to read {0} bytes, but read {1}", chunk_size, bytes_read); + } + + if (is_zero_terminated()) + break; + } + + if (!is_zero_terminated()) + return llvm::createStringError("String is 1 MiB or larger"); + + // Remove null terminator. + output.pop_back_n(is_unicode ? 2 : 1); + return llvm::Error::success(); +} + void ProcessDebugger::OnDebuggerError(const Status &error, uint32_t type) { llvm::sys::ScopedLock lock(m_mutex); Log *log = GetLog(WindowsLog::Process); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h index 25c877d5b4f17..10620b44beabf 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h @@ -14,6 +14,9 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorExtras.h" #include "llvm/Support/Mutex.h" #include "ForwardDecl.h" @@ -82,6 +85,15 @@ class ProcessDebugger { Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read); + /// Read an OUTPUT_DEBUG_STRING_INFO payload from the inferior. + /// `length_lower_word` is the OS-supplied low 16 bits of the string length; + /// the helper walks 64 KiB chunks (up to 1 MiB) until it finds the NUL + /// terminator, then strips it. Shared between ProcessWindows (in-process) + /// and NativeProcessWindows (lldb-server). + llvm::Error ReadDebugString(lldb::addr_t debug_string_addr, bool is_unicode, + uint16_t length_lower_word, + llvm::SmallVectorImpl<char> &output); + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index cd91dd23cb298..1333b6bc80e95 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -839,57 +839,6 @@ void ProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, } } -llvm::Error -ProcessWindows::ReadDebugString(lldb::addr_t debug_string_addr, bool is_unicode, - uint16_t length_lower_word, - llvm::SmallVectorImpl<char> &output) { - if (is_unicode && length_lower_word % 2 != 0) - return llvm::createStringError( - "Utf16 string can't have uneven size in bytes"); - - const auto is_zero_terminated = [&] { - // The zero terminator is always at the end of the buffer. - if (is_unicode) - return output.size() >= 2 && output.back() == 0 && - output[output.size() - 2] == 0; - - return !output.empty() && output.back() == 0; - }; - - // Read at most 1 MiB ((1 << 16) * 16 - 1 Bytes) since we don't know the exact - // size of the string. We know that `strlen(string) & 0xffff == - // length_lower_word`, so we read in chunks until we reach the terminator: - // - 0: `length_lower_word` Bytes - // - 1..16: 64 KiB (= 2^16 Bytes) - size_t start = length_lower_word == 0 ? 1 : 0; - for (size_t i = start; i < 16; ++i) { - output.resize_for_overwrite(length_lower_word + i * (1 << 16)); - size_t chunk_size = i == 0 ? length_lower_word : (1 << 16); - lldb::addr_t addr = debug_string_addr + output.size_in_bytes() - chunk_size; - - Status error; - size_t bytes_read = - DoReadMemory(addr, output.end() - chunk_size, chunk_size, error); - if (error.Fail()) - return error.takeError(); - - if (bytes_read != chunk_size) { - return llvm::createStringErrorV( - "Expected to read {0} bytes, but read {1}", chunk_size, bytes_read); - } - - if (is_zero_terminated()) - break; - } - - if (!is_zero_terminated()) - return llvm::createStringError("String is 1 MiB or larger"); - - // Remove null terminator. - output.pop_back_n(is_unicode ? 2 : 1); - return llvm::Error::success(); -} - void ProcessWindows::OnDebuggerError(const Status &error, uint32_t type) { llvm::sys::ScopedLock lock(m_mutex); Log *log = GetLog(WindowsLog::Process); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index 677ade4971eed..9c6a7528e1b31 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -121,10 +121,6 @@ class ProcessWindows : public Process, public ProcessDebugger { MemoryRegionInfo &info) override; private: - llvm::Error ReadDebugString(lldb::addr_t debug_string_addr, bool is_unicode, - uint16_t length_lower_word, - llvm::SmallVectorImpl<char> &output); - struct WatchpointInfo { uint32_t slot_id; lldb::addr_t address; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
