[Lldb-commits] [lldb] 8167678 - [lldb][windows] support long path in loaded modules cache (#206117)

via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 16 04:52:41 PDT 2026


Author: Charles Zablit
Date: 2026-09-16T12:52:35+01:00
New Revision: 8167678860e17c5c20aaaf0f863ef70861b3b9f1

URL: https://github.com/llvm/llvm-project/commit/8167678860e17c5c20aaaf0f863ef70861b3b9f1
DIFF: https://github.com/llvm/llvm-project/commit/8167678860e17c5c20aaaf0f863ef70861b3b9f1.diff

LOG: [lldb][windows] support long path in loaded modules cache (#206117)

`NativeProcessWindows::CacheLoadedModules` truncates paths longer than
260 characters.

This patch changes how modules are resolved:

- Query the untruncated image path with `GetModuleFileNameExW`.
- Canonicalize it through a handle to the image file with
`GetFinalPathNameByHandleW(FILE_NAME_NORMALIZED | VOLUME_NAME_DOS)`.
- Strip the extended length prefixes so the cached path matches the
ordinary Win32 form lldb produces elsewhere.

Added: 
    

Modified: 
    lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index 0fa3eae2c7ed6..849931eaec372 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -9,6 +9,7 @@
 #include "lldb/Host/windows/windows.h"
 #include <dbghelp.h>
 #include <excpt.h>
+#include <pathcch.h>
 #include <psapi.h>
 
 #include "NativeProcessWindows.h"
@@ -359,32 +360,95 @@ Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,
   return RemoveSoftwareBreakpoint(addr);
 }
 
+// Resolve the fully qualified, normalized on disk path of a module loaded in
+// the target process.
+static bool GetLoadedModulePath(HANDLE process, HMODULE module,
+                                std::string &path) {
+  std::vector<wchar_t> name(MAX_PATH);
+  DWORD len = 0;
+  while (true) {
+    len = ::GetModuleFileNameExW(process, module, name.data(),
+                                 static_cast<DWORD>(name.size()));
+    if (len == 0)
+      return false;
+    if (len < name.size())
+      break;
+    if (name.size() >= PATHCCH_MAX_CCH)
+      return false;
+    name.resize(name.size() * 2);
+  }
+
+  std::wstring wpath(name.data(), len);
+
+  // Canonicalize through a handle to the image file so the reported path
+  // matches the on-disk name exactly.
+  AutoHandle file(::CreateFileW(
+      wpath.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+      nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+
+  if (!file.IsValid())
+    return llvm::convertWideToUTF8(wpath, path);
+
+  // Unlike GetModuleFileNameExW, GetFinalPathNameByHandleW reports the buffer
+  // size it needs instead of truncating, so start empty and let the first call
+  // size the buffer rather than guessing.
+  std::vector<wchar_t> full;
+  while (true) {
+    DWORD needed = ::GetFinalPathNameByHandleW(
+        file.get(), full.data(), static_cast<DWORD>(full.size()),
+        FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+    if (needed == 0)
+      break;
+    if (needed < full.size()) {
+      std::wstring canonical(full.data(), needed);
+      // GetFinalPathNameByHandleW returns an extended-length ("\\?\") path.
+      static const wchar_t kUNCPrefix[] = L"\\\\?\\UNC\\";
+      static const wchar_t kDOSPrefix[] = L"\\\\?\\";
+      if (canonical.rfind(kUNCPrefix, 0) == 0)
+        canonical.replace(0, wcslen(kUNCPrefix), L"\\\\");
+      else if (canonical.rfind(kDOSPrefix, 0) == 0)
+        canonical.erase(0, wcslen(kDOSPrefix));
+      wpath = std::move(canonical);
+      break;
+    }
+    full.resize(needed);
+  }
+
+  return llvm::convertWideToUTF8(wpath, path);
+}
+
 Status NativeProcessWindows::CacheLoadedModules() {
   Status error;
   if (!m_loaded_modules.IsEmpty())
     return Status();
 
-  // Retrieve loaded modules by a Target/Module-free implementation.
-  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
-  if (snapshot.IsValid()) {
-    MODULEENTRY32W me;
-    me.dwSize = sizeof(MODULEENTRY32W);
-    if (Module32FirstW(snapshot.get(), &me)) {
-      do {
-        std::string path;
-        if (!llvm::convertWideToUTF8(me.szExePath, path))
-          continue;
-
-        FileSpec file_spec(path);
-        FileSystem::Instance().Resolve(file_spec);
-        m_loaded_modules.Add(file_spec, (addr_t)me.modBaseAddr);
-      } while (Module32Next(snapshot.get(), &me));
-    }
+  AutoHandle process(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                                   FALSE, GetID()),
+                     nullptr);
+  if (!process.IsValid())
+    return Status(::GetLastError(), eErrorTypeWin32);
+
+  AutoHandle snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
+  if (!snapshot.IsValid())
+    return Status(::GetLastError(), eErrorTypeWin32);
+
+  MODULEENTRY32W me;
+  me.dwSize = sizeof(MODULEENTRY32W);
+  if (::Module32FirstW(snapshot.get(), &me)) {
+    do {
+      std::string path;
+      if (!GetLoadedModulePath(process.get(), me.hModule, path))
+        continue;
 
-    if (!m_loaded_modules.IsEmpty())
-      return Status();
+      FileSpec file_spec(path);
+      FileSystem::Instance().Resolve(file_spec);
+      m_loaded_modules.Add(file_spec, reinterpret_cast<addr_t>(me.modBaseAddr));
+    } while (::Module32NextW(snapshot.get(), &me));
   }
 
+  if (!m_loaded_modules.IsEmpty())
+    return Status();
+
   error = Status(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
   return error;
 }


        


More information about the lldb-commits mailing list