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/6] [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/6] 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/6] 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/6] 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/6] 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/6] 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); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
