[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