[Lldb-commits] [lldb] [lldb][windows] fix duplicate OnLoadModule events (PR #189376)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 2 06:26:31 PDT 2026


https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/189376

>From 15063fdffb74030a5d9f1320330fc925c5b1ad2a Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Mon, 30 Mar 2026 14:06:43 +0100
Subject: [PATCH 1/3] [lldb][windows] fix duplicate OnLoadModule events

---
 .../Windows-DYLD/DynamicLoaderWindowsDYLD.cpp | 36 +++++++++++++------
 .../Windows-DYLD/DynamicLoaderWindowsDYLD.h   | 14 +++++---
 2 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
index 44d671f843b74..393d4e859abba 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -64,7 +64,6 @@ DynamicLoader *DynamicLoaderWindowsDYLD::CreateInstance(Process *process,
 void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
                                             const ModuleSpec module_spec,
                                             lldb::addr_t module_addr) {
-
   // Resolve the module unless we already have one.
   if (!module_sp) {
     Status error;
@@ -74,7 +73,7 @@ void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
       return;
   }
 
-  m_loaded_modules[module_sp] = module_addr;
+  m_loaded_modules[module_addr] = lldb::ModuleWP(module_sp);
   UpdateLoadedSectionsCommon(module_sp, module_addr, false);
   ModuleList module_list;
   module_list.Append(module_sp);
@@ -82,13 +81,26 @@ void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
 }
 
 void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {
-  Address resolved_addr;
-  if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
+  auto it = m_loaded_modules.find(module_addr);
+  if (it == m_loaded_modules.end())
+    return;
+
+  ModuleSP module_sp = it->second.lock();
+  m_loaded_modules.erase(it);
+
+  if (!module_sp)
     return;
 
-  ModuleSP module_sp = resolved_addr.GetModule();
-  if (module_sp) {
-    m_loaded_modules.erase(module_sp);
+  bool full_unload = true;
+  for (const auto &entry : m_loaded_modules) {
+    ModuleSP other_sp = entry.second.lock();
+    if (other_sp == module_sp) {
+      UpdateLoadedSectionsCommon(module_sp, entry.first, false);
+      full_unload = false;
+    }
+  }
+
+  if (full_unload) {
     UnloadSectionsCommon(module_sp);
     ModuleList module_list;
     module_list.Append(module_sp);
@@ -98,9 +110,11 @@ void DynamicLoaderWindowsDYLD::OnUnloadModule(lldb::addr_t module_addr) {
 
 lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {
   // First, see if the load address is already cached.
-  auto it = m_loaded_modules.find(executable);
-  if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)
-    return it->second;
+  for (const auto &entry : m_loaded_modules) {
+    ModuleSP mod = entry.second.lock();
+    if (mod == executable && entry.first != LLDB_INVALID_ADDRESS)
+      return entry.first;
+  }
 
   lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
 
@@ -112,7 +126,7 @@ lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {
       m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
   // Servers other than lldb server could respond with a bogus address.
   if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
-    m_loaded_modules[executable] = load_addr;
+    m_loaded_modules[load_addr] = lldb::ModuleWP(executable);
     return load_addr;
   }
 
diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
index 8b1c3c3f467f4..67d2104b6ef1f 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -12,8 +12,6 @@
 #include "lldb/Target/DynamicLoader.h"
 #include "lldb/lldb-forward.h"
 
-#include <map>
-
 namespace lldb_private {
 
 class DynamicLoaderWindowsDYLD : public DynamicLoader {
@@ -44,9 +42,15 @@ class DynamicLoaderWindowsDYLD : public DynamicLoader {
 protected:
   lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
 
-private:
-  std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
-      m_loaded_modules;
+  /// Maps load addresses to their corresponding modules.
+  ///
+  /// Weak pointers are used intentionally: on Windows, a Module holds a
+  /// memory-mapped view of the DLL file, and an open memory mapping locks
+  /// the file on disk. Holding a strong reference (ModuleSP) here would
+  /// prevent the mapping from being released even after the Target drops
+  /// its own reference, keeping the file locked and blocking recompilation
+  /// during an active debug session.
+  llvm::DenseMap<lldb::addr_t, lldb::ModuleWP> m_loaded_modules;
 };
 
 } // namespace lldb_private

>From 1653e622428ce5e870ae739c3428f3e969a90d18 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Mon, 30 Mar 2026 16:44:55 +0100
Subject: [PATCH 2/3] fixup! [lldb][windows] fix duplicate OnLoadModule events

---
 .../DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
index 393d4e859abba..79fb4d46eff41 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp
@@ -73,7 +73,7 @@ void DynamicLoaderWindowsDYLD::OnLoadModule(lldb::ModuleSP module_sp,
       return;
   }
 
-  m_loaded_modules[module_addr] = lldb::ModuleWP(module_sp);
+  m_loaded_modules.insert({module_addr, lldb::ModuleWP(module_sp)});
   UpdateLoadedSectionsCommon(module_sp, module_addr, false);
   ModuleList module_list;
   module_list.Append(module_sp);
@@ -126,7 +126,7 @@ lldb::addr_t DynamicLoaderWindowsDYLD::GetLoadAddress(ModuleSP executable) {
       m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
   // Servers other than lldb server could respond with a bogus address.
   if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
-    m_loaded_modules[load_addr] = lldb::ModuleWP(executable);
+    m_loaded_modules.insert({load_addr, lldb::ModuleWP(executable)});
     return load_addr;
   }
 

>From 41c0774252f548cb359e24a88f78162709fe9c31 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Thu, 2 Apr 2026 14:26:14 +0100
Subject: [PATCH 3/3] add doc comment

---
 .../Windows-DYLD/DynamicLoaderWindowsDYLD.h   | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
index 67d2104b6ef1f..eebb5117b30c5 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -40,6 +40,27 @@ class DynamicLoaderWindowsDYLD : public DynamicLoader {
   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
 
 protected:
+  /// Returns the load address for the given executable module.
+  ///
+  /// The lookup proceeds in two stages:
+  ///
+  /// 1. **Cache lookup** – \c m_loaded_modules is scanned for an existing
+  ///    entry whose \c ModuleSP matches \p executable. Because the same
+  ///    \c ModuleSP can be inserted more than once under different base
+  ///    addresses (e.g. a DLL loaded into several processes, or a module
+  ///    that was unloaded and reloaded at a different address), the scan
+  ///    returns the *first* valid (non-LLDB_INVALID_ADDRESS) entry it
+  ///    finds.
+  ///
+  /// 2. **Process / platform query** – If no cached entry is found,
+  ///    \c Process::GetFileLoadAddress is called. On a remote target the
+  ///    remote platform is responsible for resolving the address. A
+  ///    successful result is inserted into \c m_loaded_modules so that
+  ///    subsequent calls hit the cache.
+  ///
+  /// \param executable  The module whose load address is requested.
+  /// \return            The load address, or \c LLDB_INVALID_ADDRESS if it
+  ///                    could not be determined.
   lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
 
   /// Maps load addresses to their corresponding modules.



More information about the lldb-commits mailing list