https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/203334
>From d19328d298c46b186daeaba5350863a378f5de6e Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 12 Jun 2026 14:58:27 +0100 Subject: [PATCH 1/8] [lldb][Windows] Synchronize on LOAD_DLL_DEBUG_EVENT in lldb-server --- .../Process/Windows/Common/DebuggerThread.cpp | 27 ++++++++ .../Process/Windows/Common/DebuggerThread.h | 18 ++++++ .../Windows/Common/NativeProcessWindows.cpp | 61 ++++++++++++++++++- .../Windows/Common/NativeProcessWindows.h | 20 +++++- .../GDBRemoteCommunicationServerLLGS.cpp | 5 ++ 5 files changed, 128 insertions(+), 3 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index ce679d905a734..548107b67b7d6 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -208,6 +208,8 @@ Status DebuggerThread::StopDebugging(bool terminate) { ContinueAsyncException(ExceptionResult::MaskException); } + ContinueAsyncDllEvent(); + if (!terminate) { // Indicate that we want to detach. m_pid_to_detach = GetProcess().GetProcessId(); @@ -249,6 +251,31 @@ void DebuggerThread::ContinueAsyncException(ExceptionResult result) { m_exception_pred.SetValue(result, eBroadcastAlways); } +void DebuggerThread::ContinueAsyncDllEvent() { + Log *log = GetLog(WindowsLog::Process | WindowsLog::Event); + LLDB_LOG(log, "releasing parked DLL event for inferior process {0}.", + m_process.GetProcessId()); + + m_dll_event_pred.SetValue(true, eBroadcastAlways); +} + +void DebuggerThread::WaitForResumeAfterDllEvent() { + Log *log = GetLog(WindowsLog::Process | WindowsLog::Event); + + m_dll_event_pred.SetValue(false, eBroadcastNever); + m_pending_dll_event.store(true); + if (m_is_shutting_down.load()) { + m_pending_dll_event.store(false); + return; + } + LLDB_LOG(log, "parking inferior {0} on DLL event until next resume", + m_process.GetProcessId()); + m_dll_event_pred.WaitForValueEqualTo(true); + m_pending_dll_event.store(false); + LLDB_LOG(log, "inferior {0} released from DLL event wait", + m_process.GetProcessId()); +} + void DebuggerThread::FreeProcessHandles() { m_process = HostProcess(); m_main_thread = HostThread(); diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h index e0a6e9207bcd7..677d594324c27 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h @@ -42,6 +42,18 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { void ContinueAsyncException(ExceptionResult result); + /// Whether HandleLoadDllEvent / HandleUnloadDllEvent is currently parked + /// waiting for ContinueAsyncDllEvent. + bool HasPendingDllEvent() const { return m_pending_dll_event; } + + /// Block the current debugger thread until ContinueAsyncDllEvent is + /// invoked. + void WaitForResumeAfterDllEvent(); + + /// Release a HandleLoadDllEvent / HandleUnloadDllEvent that is waiting on + /// the DLL-event predicate. + void ContinueAsyncDllEvent(); + private: void FreeProcessHandles(); void DebugLoop(); @@ -76,6 +88,12 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { // and the debug loop can be continued. Predicate<ExceptionResult> m_exception_pred; + // Predicate which gets signalled when ContinueAsyncDllEvent is called. + Predicate<bool> m_dll_event_pred; + + // True while a HandleLoadDllEvent / HandleUnloadDllEvent is parked. + std::atomic<bool> m_pending_dll_event{false}; + // An event which gets signalled by the debugger thread when it exits the // debugger loop and is detached from the inferior. HANDLE m_debugging_ended_event = nullptr; diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 889a2e743c07f..ba1d1daa382f2 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -157,6 +157,8 @@ Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) { // anything happened. m_session_data->m_debugger->ContinueAsyncException( ExceptionResult::MaskException); + } else if (m_session_data->m_debugger->HasPendingDllEvent()) { + m_session_data->m_debugger->ContinueAsyncDllEvent(); } } else { LLDB_LOG(log, "error: process {0} is in state {1}. Returning...", @@ -480,6 +482,15 @@ void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { SetArchitecture(process_info.GetArchitecture()); } + ProcessInstanceInfo info; + if (Host::GetProcessInfo(GetDebuggedProcessId(), info)) { + FileSpec exe = info.GetExecutableFile(); + if (exe) { + FileSystem::Instance().Resolve(exe); + m_loaded_modules[exe] = image_base; + } + } + // The very first one shall always be the main thread. assert(m_threads.empty()); m_threads.push_back(std::make_unique<NativeThreadWindows>( @@ -704,13 +715,59 @@ void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id, void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr) { - m_loaded_modules.clear(); + Log *log = GetLog(WindowsLog::Process); + + if (module_spec.GetFileSpec()) { + FileSpec resolved = module_spec.GetFileSpec(); + FileSystem::Instance().Resolve(resolved); + m_loaded_modules[resolved] = module_addr; + } m_pending_library_events = true; + + if (!m_initial_stop_seen || !m_client_supports_libraries_read) + return; + + if (!m_threads.empty()) { + auto first = static_cast<NativeThreadWindows *>(m_threads[0].get()); + SetCurrentThreadID(first->GetID()); + if (first->DoStop().Fail()) + LLDB_LOG(log, "failed to suspend thread {0} on LOAD_DLL", first->GetID()); + ThreadStopInfo info; + info.reason = lldb::eStopReasonNone; + info.signo = 0; + first->SetStopReason(info, ""); + } + SetState(eStateStopped, true); + + m_session_data->m_debugger->WaitForResumeAfterDllEvent(); } void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { - m_loaded_modules.clear(); + Log *log = GetLog(WindowsLog::Process); + for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) { + if (it->second == module_addr) + it = m_loaded_modules.erase(it); + else + ++it; + } m_pending_library_events = true; + + if (!m_initial_stop_seen || m_client_supports_libraries_read) + return; + + if (!m_threads.empty()) { + auto first = static_cast<NativeThreadWindows *>(m_threads[0].get()); + SetCurrentThreadID(first->GetID()); + if (first->DoStop().Fail()) + LLDB_LOG(log, "failed to suspend thread {0} on UNLOAD_DLL", + first->GetID()); + ThreadStopInfo info; + info.reason = lldb::eStopReasonNone; + info.signo = 0; + first->SetStopReason(info, ""); + } + SetState(eStateStopped, true); + m_session_data->m_debugger->WaitForResumeAfterDllEvent(); } void NativeProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index e2879bcd803fe..a8bd4dff6c6e4 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -107,6 +107,20 @@ class NativeProcessWindows : public NativeProcessProtocol, bool HasPendingLibraryEvents() override; + /// Records whether the gdb-remote client advertised + /// `qXfer:libraries:read+` (or `qXfer:libraries-svr4:read+`) in its + /// qSupported reply. + void SetClientSupportsLibrariesRead(bool v) { + m_client_supports_libraries_read = v; + } + + /// Forwards to NativeProcessProtocol's bookkeeping. + void SetEnabledExtensions(Extension flags) override { + NativeProcessProtocol::SetEnabledExtensions(flags); + SetClientSupportsLibrariesRead( + bool(flags & (Extension::libraries | Extension::libraries_svr4))); + } + /// Forward bytes from the gdb-remote `I` packet into the inferior's /// ConPTY-backed stdin via `m_stdio_communication.Write` → /// `ConnectionConPTY::Write` → `WriteFile` on the parent-side STDIN @@ -163,7 +177,7 @@ class NativeProcessWindows : public NativeProcessProtocol, /// Set whenever an OS DLL load/unload event has been seen since the last stop /// reply. - bool m_pending_library_events = true; + bool m_pending_library_events = false; /// Whether we've seen the loader breakpoint that fires once per process at /// launch / attach. @@ -172,6 +186,10 @@ class NativeProcessWindows : public NativeProcessProtocol, /// Set when Halt() / Interrupt() schedules a DebugBreakProcess injection. bool m_pending_halt = false; + /// Mirrors the client-side qXfer:libraries[-svr4]:read+ qSupported feature + /// reported by GDBRemoteCommunicationServerLLGS::HandleFeatures. + bool m_client_supports_libraries_read = false; + /// PseudoConsole for the lldb-server stdio-forwarding path. std::shared_ptr<PseudoConsole> m_pty; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 0f14231cadbd5..9596eaf31c4fc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -4496,6 +4496,11 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( .Case("vfork-events+", Extension::vfork) .Default({}); + if (bool(plugin_features & Extension::libraries)) + m_extensions_supported |= Extension::libraries; + if (bool(plugin_features & Extension::libraries_svr4)) + m_extensions_supported |= Extension::libraries_svr4; + // We consume lldb's swbreak/hwbreak feature, but it doesn't change the // behaviour of lldb-server. We always adjust the program counter for targets // like x86 >From 4dbca2823a6fbfcdfc07ed220d4b83238e65fe50 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 12 Jun 2026 15:59:59 +0100 Subject: [PATCH 2/8] fixup! [lldb][Windows] Synchronize on LOAD_DLL_DEBUG_EVENT in lldb-server --- .../Process/Windows/Common/NativeProcessWindows.cpp | 9 +++------ .../Process/Windows/Common/NativeProcessWindows.h | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index ba1d1daa382f2..0bff8143cc2b3 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -744,12 +744,9 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { Log *log = GetLog(WindowsLog::Process); - for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) { - if (it->second == module_addr) - it = m_loaded_modules.erase(it); - else - ++it; - } + llvm::erase_if(m_loaded_modules, [module_addr](const auto &entry) { + return entry.second == module_addr; + }); m_pending_library_events = true; if (!m_initial_stop_seen || m_client_supports_libraries_read) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index a8bd4dff6c6e4..fe2a89e51cf32 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -107,9 +107,6 @@ class NativeProcessWindows : public NativeProcessProtocol, bool HasPendingLibraryEvents() override; - /// Records whether the gdb-remote client advertised - /// `qXfer:libraries:read+` (or `qXfer:libraries-svr4:read+`) in its - /// qSupported reply. void SetClientSupportsLibrariesRead(bool v) { m_client_supports_libraries_read = v; } >From 637bdd25a8eebcaf1751d2044aa3d7dd9fa653f9 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 12 Jun 2026 16:43:20 +0100 Subject: [PATCH 3/8] remove erase_if --- .../Process/Windows/Common/NativeProcessWindows.cpp | 9 ++++++--- .../Process/Windows/Common/NativeProcessWindows.h | 2 -- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 0bff8143cc2b3..ba1d1daa382f2 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -744,9 +744,12 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { Log *log = GetLog(WindowsLog::Process); - llvm::erase_if(m_loaded_modules, [module_addr](const auto &entry) { - return entry.second == module_addr; - }); + for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) { + if (it->second == module_addr) + it = m_loaded_modules.erase(it); + else + ++it; + } m_pending_library_events = true; if (!m_initial_stop_seen || m_client_supports_libraries_read) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index fe2a89e51cf32..d070662faeb6b 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -183,8 +183,6 @@ class NativeProcessWindows : public NativeProcessProtocol, /// Set when Halt() / Interrupt() schedules a DebugBreakProcess injection. bool m_pending_halt = false; - /// Mirrors the client-side qXfer:libraries[-svr4]:read+ qSupported feature - /// reported by GDBRemoteCommunicationServerLLGS::HandleFeatures. bool m_client_supports_libraries_read = false; /// PseudoConsole for the lldb-server stdio-forwarding path. >From 3c7a8404955d3d219e4a8493b130d404644bb861 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Mon, 15 Jun 2026 14:32:51 +0100 Subject: [PATCH 4/8] pass correct thread id --- .../Process/Windows/Common/DebuggerThread.cpp | 8 +--- .../Process/Windows/Common/IDebugDelegate.h | 4 +- .../Windows/Common/LocalDebugDelegate.cpp | 10 +++-- .../Windows/Common/LocalDebugDelegate.h | 4 +- .../Windows/Common/NativeProcessWindows.cpp | 44 ++++++++++++------- .../Windows/Common/NativeProcessWindows.h | 14 +++--- .../Windows/Common/ProcessDebugger.cpp | 6 ++- .../Process/Windows/Common/ProcessDebugger.h | 4 +- .../Process/Windows/Common/ProcessWindows.cpp | 6 ++- .../Process/Windows/Common/ProcessWindows.h | 6 +-- lldb/test/API/lit.cfg.py | 2 +- 11 files changed, 62 insertions(+), 46 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index 548107b67b7d6..a7c7b7c7cd6a5 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -252,10 +252,6 @@ void DebuggerThread::ContinueAsyncException(ExceptionResult result) { } void DebuggerThread::ContinueAsyncDllEvent() { - Log *log = GetLog(WindowsLog::Process | WindowsLog::Event); - LLDB_LOG(log, "releasing parked DLL event for inferior process {0}.", - m_process.GetProcessId()); - m_dll_event_pred.SetValue(true, eBroadcastAlways); } @@ -725,7 +721,7 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, LLDB_LOG(log, "Inferior {0} - DLL '{1}' loaded at address {2:x}...", m_process.GetProcessId(), path, info.lpBaseOfDll); - m_debug_delegate->OnLoadDll(module_spec, load_addr); + m_debug_delegate->OnLoadDll(module_spec, load_addr, thread_id); }; std::optional<std::string> resolved_path; @@ -776,7 +772,7 @@ DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, m_process.GetProcessId(), info.lpBaseOfDll); m_debug_delegate->OnUnloadDll( - reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll)); + reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll), thread_id); return DBG_CONTINUE; } diff --git a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h index 049d72fafeb72..b0903ef18522f 100644 --- a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h @@ -33,8 +33,8 @@ class IDebugDelegate { virtual void OnCreateThread(const HostThread &thread) = 0; virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0; virtual void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) = 0; - virtual void OnUnloadDll(lldb::addr_t module_addr) = 0; + lldb::addr_t module_addr, lldb::tid_t thread_id) = 0; + virtual void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) = 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.cpp b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp index 647502ddaac25..14579ce350a34 100644 --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp @@ -46,14 +46,16 @@ void LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, } void LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) { + lldb::addr_t module_addr, + lldb::tid_t thread_id) { if (ProcessWindowsSP process = GetProcessPointer()) - process->OnLoadDll(module_spec, module_addr); + process->OnLoadDll(module_spec, module_addr, thread_id); } -void LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr) { +void LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr, + lldb::tid_t thread_id) { if (ProcessWindowsSP process = GetProcessPointer()) - process->OnUnloadDll(module_addr); + process->OnUnloadDll(module_addr, thread_id); } void LocalDebugDelegate::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h index 91f0fb64edaba..96e009304130a 100644 --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h @@ -49,8 +49,8 @@ class LocalDebugDelegate : public IDebugDelegate { void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; void OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; + lldb::addr_t module_addr, lldb::tid_t thread_id) override; + void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) 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; diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index ba1d1daa382f2..3a0540c11eeed 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -714,7 +714,8 @@ void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id, } void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { + lldb::addr_t module_addr, + lldb::tid_t thread_id) { Log *log = GetLog(WindowsLog::Process); if (module_spec.GetFileSpec()) { @@ -727,22 +728,29 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, if (!m_initial_stop_seen || !m_client_supports_libraries_read) return; - if (!m_threads.empty()) { - auto first = static_cast<NativeThreadWindows *>(m_threads[0].get()); - SetCurrentThreadID(first->GetID()); - if (first->DoStop().Fail()) - LLDB_LOG(log, "failed to suspend thread {0} on LOAD_DLL", first->GetID()); + NativeThreadWindows *loader_thread = GetThreadByID(thread_id); + if (!loader_thread && !m_threads.empty()) { + LLDB_LOG(log, "LOAD_DLL on unknown tid {0:x}. Falling back to main thread.", + thread_id); + loader_thread = static_cast<NativeThreadWindows *>(m_threads[0].get()); + } + if (loader_thread) { + SetCurrentThreadID(loader_thread->GetID()); + if (loader_thread->DoStop().Fail()) + LLDB_LOG(log, "Failed to suspend thread {0} on LOAD_DLL.", + loader_thread->GetID()); ThreadStopInfo info; info.reason = lldb::eStopReasonNone; info.signo = 0; - first->SetStopReason(info, ""); + loader_thread->SetStopReason(info, ""); } SetState(eStateStopped, true); m_session_data->m_debugger->WaitForResumeAfterDllEvent(); } -void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { +void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, + lldb::tid_t thread_id) { Log *log = GetLog(WindowsLog::Process); for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) { if (it->second == module_addr) @@ -755,16 +763,22 @@ void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { if (!m_initial_stop_seen || m_client_supports_libraries_read) return; - if (!m_threads.empty()) { - auto first = static_cast<NativeThreadWindows *>(m_threads[0].get()); - SetCurrentThreadID(first->GetID()); - if (first->DoStop().Fail()) - LLDB_LOG(log, "failed to suspend thread {0} on UNLOAD_DLL", - first->GetID()); + NativeThreadWindows *unloader_thread = GetThreadByID(thread_id); + if (!unloader_thread && !m_threads.empty()) { + LLDB_LOG(log, + "UNLOAD_DLL on unknown tid {0:x}. Falling back to main thread.", + thread_id); + unloader_thread = static_cast<NativeThreadWindows *>(m_threads[0].get()); + } + if (unloader_thread) { + SetCurrentThreadID(unloader_thread->GetID()); + if (unloader_thread->DoStop().Fail()) + LLDB_LOG(log, "Failed to suspend thread {0} on UNLOAD_DLL.", + unloader_thread->GetID()); ThreadStopInfo info; info.reason = lldb::eStopReasonNone; info.signo = 0; - first->SetStopReason(info, ""); + unloader_thread->SetStopReason(info, ""); } SetState(eStateStopped, true); m_session_data->m_debugger->WaitForResumeAfterDllEvent(); diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index d070662faeb6b..ecdda28b8e2bb 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -132,9 +132,9 @@ class NativeProcessWindows : public NativeProcessProtocol, const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; + void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, + lldb::tid_t thread_id) override; + void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override; void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, uint16_t length_lower_word) override; @@ -232,12 +232,12 @@ class NativeDebugDelegate : public IDebugDelegate { } void OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) override { - m_process.OnLoadDll(module_spec, module_addr); + lldb::addr_t module_addr, lldb::tid_t thread_id) override { + m_process.OnLoadDll(module_spec, module_addr, thread_id); } - void OnUnloadDll(lldb::addr_t module_addr) override { - m_process.OnUnloadDll(module_addr); + void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override { + m_process.OnUnloadDll(module_addr, thread_id); } void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp index 84c74bb1ba919..66272ca83e788 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp @@ -541,11 +541,13 @@ void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { } void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { + lldb::addr_t module_addr, + lldb::tid_t thread_id) { // Do nothing by default } -void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr) { +void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr, + lldb::tid_t thread_id) { // Do nothing by default } diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h index 10620b44beabf..67de4076a149c 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h @@ -60,8 +60,8 @@ class ProcessDebugger { virtual void OnCreateThread(const HostThread &thread); virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code); virtual void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr); - virtual void OnUnloadDll(lldb::addr_t module_addr); + lldb::addr_t module_addr, lldb::tid_t thread_id); + virtual void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id); 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); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 1333b6bc80e95..44d1623585a92 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -794,12 +794,14 @@ void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { } void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) { + lldb::addr_t module_addr, + lldb::tid_t thread_id) { if (auto dyld = GetDynamicLoader()) dyld->OnLoadModule(nullptr, module_spec, module_addr); } -void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr) { +void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr, + lldb::tid_t thread_id) { if (auto dyld = GetDynamicLoader()) dyld->OnUnloadModule(module_addr); } diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index 9c6a7528e1b31..c13897bbbcc34 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -88,9 +88,9 @@ class ProcessWindows : public Process, public ProcessDebugger { const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const ModuleSpec &module_spec, - lldb::addr_t module_addr) override; - void OnUnloadDll(lldb::addr_t module_addr) override; + void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, + lldb::tid_t thread_id) override; + void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) 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; diff --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py index ac2301b361da2..ab73d951e4986 100644 --- a/lldb/test/API/lit.cfg.py +++ b/lldb/test/API/lit.cfg.py @@ -203,7 +203,7 @@ def delete_module_cache(path): # lit complains if the value is set but it is not supported. supported, errormsg = lit_config.maxIndividualTestTimeIsSupported if supported: - config.maxIndividualTestTime = 600 + config.maxIndividualTestTime = 200 else: lit_config.warning("Could not set a default per-test timeout. " + errormsg) >From 742b2f99a5c48ebbb8d837cdd2595a8d90805b23 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Mon, 15 Jun 2026 16:00:07 +0200 Subject: [PATCH 5/8] Update lit.cfg.py --- lldb/test/API/lit.cfg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/lit.cfg.py b/lldb/test/API/lit.cfg.py index ab73d951e4986..ac2301b361da2 100644 --- a/lldb/test/API/lit.cfg.py +++ b/lldb/test/API/lit.cfg.py @@ -203,7 +203,7 @@ def delete_module_cache(path): # lit complains if the value is set but it is not supported. supported, errormsg = lit_config.maxIndividualTestTimeIsSupported if supported: - config.maxIndividualTestTime = 200 + config.maxIndividualTestTime = 600 else: lit_config.warning("Could not set a default per-test timeout. " + errormsg) >From 245f24cb39dd7e5f7538679c13f6af22ac41a7f6 Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Thu, 18 Jun 2026 17:52:26 +0100 Subject: [PATCH 6/8] Update lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp Co-authored-by: Jonas Devlieghere <[email protected]> --- .../Plugins/Process/Windows/Common/NativeProcessWindows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index 3a0540c11eeed..e4825bbbeb1cb 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -760,7 +760,7 @@ void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, } m_pending_library_events = true; - if (!m_initial_stop_seen || m_client_supports_libraries_read) + if (!m_initial_stop_seen || !m_client_supports_libraries_read) return; NativeThreadWindows *unloader_thread = GetThreadByID(thread_id); >From 612fe05e82a421b194d0d3caecfbd5241ebe833d Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Fri, 19 Jun 2026 16:30:54 +0100 Subject: [PATCH 7/8] fixup! [lldb][Windows] Synchronize on LOAD_DLL_DEBUG_EVENT in lldb-server --- .../Process/Windows/Common/DebuggerThread.cpp | 7 +++++-- .../Plugins/Process/Windows/Common/DebuggerThread.h | 7 ++++++- .../Process/Windows/Common/NativeProcessWindows.cpp | 13 ++++++++----- .../gdb-remote/GDBRemoteCommunicationClient.cpp | 4 +++- .../gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 7 ++----- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index a7c7b7c7cd6a5..d2d1f0bf4196e 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -255,11 +255,14 @@ void DebuggerThread::ContinueAsyncDllEvent() { m_dll_event_pred.SetValue(true, eBroadcastAlways); } +void DebuggerThread::ArmDllEventWait() { + m_dll_event_pred.SetValue(false, eBroadcastNever); + m_pending_dll_event.store(true); +} + void DebuggerThread::WaitForResumeAfterDllEvent() { Log *log = GetLog(WindowsLog::Process | WindowsLog::Event); - m_dll_event_pred.SetValue(false, eBroadcastNever); - m_pending_dll_event.store(true); if (m_is_shutting_down.load()) { m_pending_dll_event.store(false); return; diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h index 677d594324c27..7e27b7150141e 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h @@ -46,8 +46,13 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { /// waiting for ContinueAsyncDllEvent. bool HasPendingDllEvent() const { return m_pending_dll_event; } + /// Mark a DLL-event wait as pending so a Resume that arrives between the + /// SetState(eStateStopped) broadcast and WaitForResumeAfterDllEvent does + /// not race past the predicate. + void ArmDllEventWait(); + /// Block the current debugger thread until ContinueAsyncDllEvent is - /// invoked. + /// invoked. ArmDllEventWait must have been called first. void WaitForResumeAfterDllEvent(); /// Release a HandleLoadDllEvent / HandleUnloadDllEvent that is waiting on diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index e4825bbbeb1cb..f19920b0d4f12 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -472,18 +472,19 @@ void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) { if (GetID() == LLDB_INVALID_PROCESS_ID) SetID(GetDebuggedProcessId()); + ProcessInstanceInfo info; + bool got_info = Host::GetProcessInfo(GetDebuggedProcessId(), info); + if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) { - ProcessInstanceInfo process_info; - if (!Host::GetProcessInfo(GetDebuggedProcessId(), process_info)) { + if (!got_info) { LLDB_LOG(log, "Cannot get process information during debugger connecting " "to process"); return; } - SetArchitecture(process_info.GetArchitecture()); + SetArchitecture(info.GetArchitecture()); } - ProcessInstanceInfo info; - if (Host::GetProcessInfo(GetDebuggedProcessId(), info)) { + if (got_info) { FileSpec exe = info.GetExecutableFile(); if (exe) { FileSystem::Instance().Resolve(exe); @@ -744,6 +745,7 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, info.signo = 0; loader_thread->SetStopReason(info, ""); } + m_session_data->m_debugger->ArmDllEventWait(); SetState(eStateStopped, true); m_session_data->m_debugger->WaitForResumeAfterDllEvent(); @@ -780,6 +782,7 @@ void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, info.signo = 0; unloader_thread->SetStopReason(info, ""); } + m_session_data->m_debugger->ArmDllEventWait(); SetState(eStateStopped, true); m_session_data->m_debugger->WaitForResumeAfterDllEvent(); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index e79d9d2ec1bab..e4df94870fda8 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -468,7 +468,9 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { "fork-events+", "vfork-events+", "swbreak+", - "hwbreak+"}; + "hwbreak+", + "qXfer:libraries:read+", + "qXfer:libraries-svr4:read+"}; StreamString packet; packet.PutCString("qSupported"); for (uint32_t i = 0; i < features.size(); ++i) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 9596eaf31c4fc..bfefd36838723 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -4494,13 +4494,10 @@ std::vector<std::string> GDBRemoteCommunicationServerLLGS::HandleFeatures( .Case("multiprocess+", Extension::multiprocess) .Case("fork-events+", Extension::fork) .Case("vfork-events+", Extension::vfork) + .Case("qXfer:libraries:read+", Extension::libraries) + .Case("qXfer:libraries-svr4:read+", Extension::libraries_svr4) .Default({}); - if (bool(plugin_features & Extension::libraries)) - m_extensions_supported |= Extension::libraries; - if (bool(plugin_features & Extension::libraries_svr4)) - m_extensions_supported |= Extension::libraries_svr4; - // We consume lldb's swbreak/hwbreak feature, but it doesn't change the // behaviour of lldb-server. We always adjust the program counter for targets // like x86 >From ae283f42dc3045206a9a508d828cf8f18cfb401b Mon Sep 17 00:00:00 2001 From: Charles Zablit <[email protected]> Date: Mon, 22 Jun 2026 12:09:02 +0100 Subject: [PATCH 8/8] mirror exception path --- .../Process/Windows/Common/DebuggerThread.cpp | 32 +++----- .../Process/Windows/Common/DebuggerThread.h | 24 ++---- .../Process/Windows/Common/IDebugDelegate.h | 4 +- .../Windows/Common/LocalDebugDelegate.cpp | 10 ++- .../Windows/Common/LocalDebugDelegate.h | 4 +- .../Windows/Common/NativeProcessWindows.cpp | 79 ++++++++++++++++--- .../Windows/Common/NativeProcessWindows.h | 12 +-- .../Windows/Common/ProcessDebugger.cpp | 8 +- .../Process/Windows/Common/ProcessDebugger.h | 4 +- .../Process/Windows/Common/ProcessWindows.cpp | 6 +- .../Process/Windows/Common/ProcessWindows.h | 4 +- 11 files changed, 111 insertions(+), 76 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp index d2d1f0bf4196e..9d2b5daca6aca 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp @@ -255,26 +255,6 @@ void DebuggerThread::ContinueAsyncDllEvent() { m_dll_event_pred.SetValue(true, eBroadcastAlways); } -void DebuggerThread::ArmDllEventWait() { - m_dll_event_pred.SetValue(false, eBroadcastNever); - m_pending_dll_event.store(true); -} - -void DebuggerThread::WaitForResumeAfterDllEvent() { - Log *log = GetLog(WindowsLog::Process | WindowsLog::Event); - - if (m_is_shutting_down.load()) { - m_pending_dll_event.store(false); - return; - } - LLDB_LOG(log, "parking inferior {0} on DLL event until next resume", - m_process.GetProcessId()); - m_dll_event_pred.WaitForValueEqualTo(true); - m_pending_dll_event.store(false); - LLDB_LOG(log, "inferior {0} released from DLL event wait", - m_process.GetProcessId()); -} - void DebuggerThread::FreeProcessHandles() { m_process = HostProcess(); m_main_thread = HostThread(); @@ -716,6 +696,7 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id) { Log *log = GetLog(WindowsLog::Event); + bool wants_park = false; auto on_load_dll = [&](llvm::StringRef path) { FileSpec file_spec(path); ModuleSpec module_spec(file_spec); @@ -724,7 +705,8 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, LLDB_LOG(log, "Inferior {0} - DLL '{1}' loaded at address {2:x}...", m_process.GetProcessId(), path, info.lpBaseOfDll); - m_debug_delegate->OnLoadDll(module_spec, load_addr, thread_id); + m_dll_event_pred.SetValue(false, eBroadcastNever); + wants_park = m_debug_delegate->OnLoadDll(module_spec, load_addr, thread_id); }; std::optional<std::string> resolved_path; @@ -764,6 +746,9 @@ DebuggerThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, // Windows does not automatically close info.hFile, so we need to do it. if (info.hFile != nullptr) ::CloseHandle(info.hFile); + + if (wants_park && !m_is_shutting_down.load()) + m_dll_event_pred.WaitForValueEqualTo(true); return DBG_CONTINUE; } @@ -774,8 +759,11 @@ DebuggerThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, LLDB_LOG(log, "process {0} unloading DLL at addr {1:x}.", m_process.GetProcessId(), info.lpBaseOfDll); - m_debug_delegate->OnUnloadDll( + m_dll_event_pred.SetValue(false, eBroadcastNever); + bool wants_park = m_debug_delegate->OnUnloadDll( reinterpret_cast<lldb::addr_t>(info.lpBaseOfDll), thread_id); + if (wants_park && !m_is_shutting_down.load()) + m_dll_event_pred.WaitForValueEqualTo(true); return DBG_CONTINUE; } diff --git a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h index 7e27b7150141e..70204e2f9e5eb 100644 --- a/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.h @@ -42,21 +42,9 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { void ContinueAsyncException(ExceptionResult result); - /// Whether HandleLoadDllEvent / HandleUnloadDllEvent is currently parked - /// waiting for ContinueAsyncDllEvent. - bool HasPendingDllEvent() const { return m_pending_dll_event; } - - /// Mark a DLL-event wait as pending so a Resume that arrives between the - /// SetState(eStateStopped) broadcast and WaitForResumeAfterDllEvent does - /// not race past the predicate. - void ArmDllEventWait(); - - /// Block the current debugger thread until ContinueAsyncDllEvent is - /// invoked. ArmDllEventWait must have been called first. - void WaitForResumeAfterDllEvent(); - - /// Release a HandleLoadDllEvent / HandleUnloadDllEvent that is waiting on - /// the DLL-event predicate. + /// Release a HandleLoadDllEvent / HandleUnloadDllEvent that is parked on + /// m_dll_event_pred. The delegate's Resume() path calls this to let the + /// debug loop issue ContinueDebugEvent. Mirrors ContinueAsyncException. void ContinueAsyncDllEvent(); private: @@ -93,12 +81,10 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { // and the debug loop can be continued. Predicate<ExceptionResult> m_exception_pred; - // Predicate which gets signalled when ContinueAsyncDllEvent is called. + // Predicate gated by HandleLoadDllEvent / HandleUnloadDllEvent when the + // delegate asks them to park. Predicate<bool> m_dll_event_pred; - // True while a HandleLoadDllEvent / HandleUnloadDllEvent is parked. - std::atomic<bool> m_pending_dll_event{false}; - // An event which gets signalled by the debugger thread when it exits the // debugger loop and is detached from the inferior. HANDLE m_debugging_ended_event = nullptr; diff --git a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h index b0903ef18522f..7ab7deda680d9 100644 --- a/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/IDebugDelegate.h @@ -32,9 +32,9 @@ class IDebugDelegate { const ExceptionRecord &record) = 0; virtual void OnCreateThread(const HostThread &thread) = 0; virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) = 0; - virtual void OnLoadDll(const ModuleSpec &module_spec, + virtual bool OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) = 0; - virtual void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) = 0; + virtual bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) = 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.cpp b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp index 14579ce350a34..44299024cf28e 100644 --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp @@ -45,17 +45,19 @@ void LocalDebugDelegate::OnExitThread(lldb::tid_t thread_id, process->OnExitThread(thread_id, exit_code); } -void LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, +bool LocalDebugDelegate::OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) { if (ProcessWindowsSP process = GetProcessPointer()) - process->OnLoadDll(module_spec, module_addr, thread_id); + return process->OnLoadDll(module_spec, module_addr, thread_id); + return false; } -void LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr, +bool LocalDebugDelegate::OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) { if (ProcessWindowsSP process = GetProcessPointer()) - process->OnUnloadDll(module_addr, thread_id); + return process->OnUnloadDll(module_addr, thread_id); + return false; } void LocalDebugDelegate::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h index 96e009304130a..a9d7bf92ac445 100644 --- a/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h +++ b/lldb/source/Plugins/Process/Windows/Common/LocalDebugDelegate.h @@ -48,9 +48,9 @@ class LocalDebugDelegate : public IDebugDelegate { const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, + bool OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) override; - void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override; + bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) 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; diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index f19920b0d4f12..00b81565cc47f 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -50,6 +50,55 @@ using namespace llvm; namespace lldb_private { +namespace { + +/// Whether \a spec lives under the OS's system directory tree (e.g. +/// `C:\Windows\System32\*`, `C:\Windows\SysWOW64\*`, `C:\Windows\WinSxS\*`). +bool IsSystemDLL(const FileSpec &spec) { + if (!spec) + return false; + + static const std::vector<std::string> system_prefixes = []() { + std::vector<std::string> prefixes; + auto add_dir = [&](UINT (*query)(LPWSTR, UINT)) { + wchar_t buf[MAX_PATH]; + UINT len = query(buf, MAX_PATH); + if (len == 0 || len >= MAX_PATH) + return; + std::string utf8; + llvm::convertWideToUTF8(std::wstring_view(buf, len), utf8); + // Normalize to lowercase + backslash + trailing separator so a simple + // prefix match against an equally-normalized path is correct. + for (char &c : utf8) { + if (c == '/') + c = '\\'; + else + c = std::tolower(static_cast<unsigned char>(c)); + } + if (!utf8.empty() && utf8.back() != '\\') + utf8 += '\\'; + prefixes.push_back(std::move(utf8)); + }; + add_dir(::GetSystemDirectoryW); // C:\Windows\System32 + add_dir(::GetWindowsDirectoryW); // C:\Windows + return prefixes; + }(); + + std::string path = spec.GetPath(); + for (char &c : path) { + if (c == '/') + c = '\\'; + else + c = std::tolower(static_cast<unsigned char>(c)); + } + for (const std::string &prefix : system_prefixes) + if (llvm::StringRef(path).starts_with(prefix)) + return true; + return false; +} + +} // namespace + NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info, NativeDelegate &delegate, llvm::Error &E) @@ -157,7 +206,7 @@ Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) { // anything happened. m_session_data->m_debugger->ContinueAsyncException( ExceptionResult::MaskException); - } else if (m_session_data->m_debugger->HasPendingDllEvent()) { + } else { m_session_data->m_debugger->ContinueAsyncDllEvent(); } } else { @@ -714,7 +763,7 @@ void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id, }); } -void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, +bool NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) { Log *log = GetLog(WindowsLog::Process); @@ -727,7 +776,11 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, m_pending_library_events = true; if (!m_initial_stop_seen || !m_client_supports_libraries_read) - return; + return false; + + // Can't resolve a breakpoint in a system DLL. + if (IsSystemDLL(module_spec.GetFileSpec())) + return false; NativeThreadWindows *loader_thread = GetThreadByID(thread_id); if (!loader_thread && !m_threads.empty()) { @@ -745,25 +798,30 @@ void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec, info.signo = 0; loader_thread->SetStopReason(info, ""); } - m_session_data->m_debugger->ArmDllEventWait(); SetState(eStateStopped, true); - m_session_data->m_debugger->WaitForResumeAfterDllEvent(); + return true; } -void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, +bool NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) { Log *log = GetLog(WindowsLog::Process); + FileSpec unloaded_spec; for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) { - if (it->second == module_addr) + if (it->second == module_addr) { + unloaded_spec = it->first; it = m_loaded_modules.erase(it); - else + } else { ++it; + } } m_pending_library_events = true; if (!m_initial_stop_seen || !m_client_supports_libraries_read) - return; + return false; + + if (IsSystemDLL(unloaded_spec)) + return false; NativeThreadWindows *unloader_thread = GetThreadByID(thread_id); if (!unloader_thread && !m_threads.empty()) { @@ -782,9 +840,8 @@ void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr, info.signo = 0; unloader_thread->SetStopReason(info, ""); } - m_session_data->m_debugger->ArmDllEventWait(); SetState(eStateStopped, true); - m_session_data->m_debugger->WaitForResumeAfterDllEvent(); + return true; } void NativeProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index ecdda28b8e2bb..8be3955ec6416 100644 --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -132,9 +132,9 @@ class NativeProcessWindows : public NativeProcessProtocol, const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, + bool OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) override; - void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override; + bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override; void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, uint16_t length_lower_word) override; @@ -231,13 +231,13 @@ class NativeDebugDelegate : public IDebugDelegate { m_process.OnExitThread(thread_id, exit_code); } - void OnLoadDll(const lldb_private::ModuleSpec &module_spec, + bool OnLoadDll(const lldb_private::ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) override { - m_process.OnLoadDll(module_spec, module_addr, thread_id); + return m_process.OnLoadDll(module_spec, module_addr, thread_id); } - void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override { - m_process.OnUnloadDll(module_addr, thread_id); + bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override { + return m_process.OnUnloadDll(module_addr, thread_id); } void OnDebugString(lldb::addr_t debug_string_addr, bool is_unicode, diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp index 66272ca83e788..b612b86b02803 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp @@ -540,15 +540,15 @@ void ProcessDebugger::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { // Do nothing by default } -void ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec, +bool ProcessDebugger::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) { - // Do nothing by default + return false; } -void ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr, +bool ProcessDebugger::OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) { - // Do nothing by default + return false; } void ProcessDebugger::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h index 67de4076a149c..5a17a017814e6 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.h @@ -59,9 +59,9 @@ class ProcessDebugger { const ExceptionRecord &record); virtual void OnCreateThread(const HostThread &thread); virtual void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code); - virtual void OnLoadDll(const ModuleSpec &module_spec, + virtual bool OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id); - virtual void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id); + virtual bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id); 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); diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 44d1623585a92..ecd9ba17594a1 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -793,17 +793,19 @@ void ProcessWindows::OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { m_session_data->m_exited_threads.insert(thread_id); } -void ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, +bool ProcessWindows::OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) { if (auto dyld = GetDynamicLoader()) dyld->OnLoadModule(nullptr, module_spec, module_addr); + return false; } -void ProcessWindows::OnUnloadDll(lldb::addr_t module_addr, +bool ProcessWindows::OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) { if (auto dyld = GetDynamicLoader()) dyld->OnUnloadModule(module_addr); + return false; } void ProcessWindows::OnDebugString(lldb::addr_t debug_string_addr, diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index c13897bbbcc34..d142a017a7ea5 100644 --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -88,9 +88,9 @@ class ProcessWindows : public Process, public ProcessDebugger { const ExceptionRecord &record) override; void OnCreateThread(const HostThread &thread) override; void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override; - void OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, + bool OnLoadDll(const ModuleSpec &module_spec, lldb::addr_t module_addr, lldb::tid_t thread_id) override; - void OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) override; + bool OnUnloadDll(lldb::addr_t module_addr, lldb::tid_t thread_id) 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; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
