[Lldb-commits] [lldb] [lldb][Windows] Key lldb-server's loaded-module list by base address (PR #223445)

via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 14 08:50:29 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)

<details>
<summary>Changes</summary>

`NativeProcessWindows` keys `m_loaded_modules` by `FileSpec`, so a second mapping of an already-loaded DLL overwrites the first one's base address, and `OnUnloadDll` then erases by address. The wrong mapping gets dropped.

This reproduces reliably in swiftlang where `swiftCore.dll` is loaded twice.

Key mappings by base address instead (the identity `UNLOAD_DLL` carries), so an unload resolves to the right file and only retires the reported entry when it is that file's last mapping.

---
Full diff: https://github.com/llvm/llvm-project/pull/223445.diff


2 Files Affected:

- (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp (+32-12) 
- (modified) lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h (+15) 


``````````diff
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index bb1feca5eb097..86bb5c283bfa7 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -358,6 +358,34 @@ Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
   return RemoveSoftwareBreakpoint(addr);
 }
 
+void NativeProcessWindows::AddLoadedModule(const FileSpec &file_spec,
+                                           addr_t base_addr) {
+  m_module_addresses[base_addr] = file_spec;
+  m_loaded_modules.try_emplace(file_spec, base_addr);
+}
+
+FileSpec NativeProcessWindows::RemoveLoadedModule(addr_t base_addr) {
+  auto addr_it = m_module_addresses.find(base_addr);
+  if (addr_it == m_module_addresses.end())
+    return {};
+
+  FileSpec file_spec = addr_it->second;
+  m_module_addresses.erase(addr_it);
+
+  auto module_it = m_loaded_modules.find(file_spec);
+  if (module_it == m_loaded_modules.end() || module_it->second != base_addr)
+    return {};
+
+  for (const auto &[addr, spec] : m_module_addresses)
+    if (spec == file_spec) {
+      module_it->second = addr;
+      return {};
+    }
+
+  m_loaded_modules.erase(module_it);
+  return file_spec;
+}
+
 Status NativeProcessWindows::CacheLoadedModules() {
   Status error;
   if (!m_loaded_modules.empty())
@@ -376,7 +404,7 @@ Status NativeProcessWindows::CacheLoadedModules() {
 
         FileSpec file_spec(path);
         FileSystem::Instance().Resolve(file_spec);
-        m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;
+        AddLoadedModule(file_spec, (addr_t)me.modBaseAddr);
       } while (Module32Next(snapshot.get(), &me));
     }
 
@@ -492,7 +520,7 @@ void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {
     FileSpec exe = info.GetExecutableFile();
     if (exe) {
       FileSystem::Instance().Resolve(exe);
-      m_loaded_modules[exe] = image_base;
+      AddLoadedModule(exe, image_base);
     }
   }
 
@@ -742,7 +770,7 @@ DllEventAction NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,
   FileSpec resolved = module_spec.GetFileSpec();
   if (resolved) {
     FileSystem::Instance().Resolve(resolved);
-    m_loaded_modules[resolved] = module_addr;
+    AddLoadedModule(resolved, module_addr);
   }
   m_pending_library_events = true;
 
@@ -779,15 +807,7 @@ DllEventAction NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr,
   Log *log = GetLog(WindowsLog::Process);
   llvm::sys::ScopedLock lock(m_mutex);
 
-  FileSpec unloaded_spec;
-  for (auto it = m_loaded_modules.begin(); it != m_loaded_modules.end();) {
-    if (it->second == module_addr) {
-      unloaded_spec = it->first;
-      it = m_loaded_modules.erase(it);
-    } else {
-      ++it;
-    }
-  }
+  FileSpec unloaded_spec = RemoveLoadedModule(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 3074eea1bc932..16f61d5062256 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h
@@ -172,8 +172,23 @@ class NativeProcessWindows : public NativeProcessProtocol,
                                          const ExceptionRecord &record);
 
   Status CacheLoadedModules();
+
+  /// Record that \p file_spec is mapped at \p base_addr.
+  void AddLoadedModule(const lldb_private::FileSpec &file_spec,
+                       lldb::addr_t base_addr);
+
+  /// Drop the mapping at \p base_addr. \return the module's file spec if this
+  /// was the last mapping of that file, an empty FileSpec otherwise.
+  lldb_private::FileSpec RemoveLoadedModule(lldb::addr_t base_addr);
+
+  /// The loaded modules to report to the client, one entry per file. The same
+  /// file can be mapped more than once.
   std::map<lldb_private::FileSpec, lldb::addr_t> m_loaded_modules;
 
+  /// Every image mapping, keyed by base address. This is the identity an
+  /// UNLOAD_DLL_DEBUG_EVENT carries.
+  std::map<lldb::addr_t, lldb_private::FileSpec> m_module_addresses;
+
   /// Set whenever an OS DLL load/unload event has been seen since the last stop
   /// reply.
   bool m_pending_library_events = false;

``````````

</details>


https://github.com/llvm/llvm-project/pull/223445


More information about the lldb-commits mailing list