[Lldb-commits] [lldb] [lldb][windows] support long path in loaded modules cache (PR #206117)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Wed Jul 15 04:25:30 PDT 2026
https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/206117
>From 451a57ee3e8b1da968e48cae1c7c5ffe22e98762 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Fri, 26 Jun 2026 16:52:40 +0100
Subject: [PATCH 1/2] [lldb][windows] support long path in loaded modules cache
---
.../Windows/Common/NativeProcessWindows.cpp | 65 ++++++++++++++-----
1 file changed, 48 insertions(+), 17 deletions(-)
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index ada92894efc47..146e053dbd867 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"
@@ -397,27 +398,57 @@ Status NativeProcessWindows::CacheLoadedModules() {
if (!m_loaded_modules.empty())
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[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);
+
+ std::vector<HMODULE> modules(256);
+ DWORD bytes_needed = 0;
+ while (true) {
+ if (!::EnumProcessModulesEx(
+ process.get(), modules.data(),
+ static_cast<DWORD>(modules.size() * sizeof(HMODULE)), &bytes_needed,
+ LIST_MODULES_ALL))
+ return Status(::GetLastError(), eErrorTypeWin32);
+ size_t count = bytes_needed / sizeof(HMODULE);
+ if (count <= modules.size()) {
+ modules.resize(count);
+ break;
}
+ modules.resize(count);
+ }
- if (!m_loaded_modules.empty())
- return Status();
+ for (HMODULE hmod : modules) {
+ std::vector<wchar_t> name(MAX_PATH);
+ DWORD len = 0;
+ while (name.size() <= PATHCCH_MAX_CCH) {
+ len = ::GetModuleFileNameExW(process.get(), hmod, name.data(),
+ static_cast<DWORD>(name.size()));
+ if (len == 0 || len < name.size())
+ break;
+ name.resize(name.size() * 2);
+ }
+ if (len == 0)
+ continue;
+
+ std::string path;
+ if (!llvm::convertWideToUTF8(std::wstring(name.data(), len), path))
+ continue;
+
+ MODULEINFO mi = {};
+ if (!::GetModuleInformation(process.get(), hmod, &mi, sizeof(mi)))
+ continue;
+
+ FileSpec file_spec(path);
+ FileSystem::Instance().Resolve(file_spec);
+ m_loaded_modules[file_spec] = reinterpret_cast<addr_t>(mi.lpBaseOfDll);
}
+ if (!m_loaded_modules.empty())
+ return Status();
+
error = Status(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);
return error;
}
>From 289a9dfe89fa2bdb49bea6f593191bf2d9d02465 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Wed, 15 Jul 2026 12:23:57 +0100
Subject: [PATCH 2/2] fixup! [lldb][windows] support long path in loaded
modules cache
---
.../Windows/Common/NativeProcessWindows.cpp | 110 +++++++++++-------
1 file changed, 71 insertions(+), 39 deletions(-)
diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index 146e053dbd867..ae3d677ce01c1 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -393,57 +393,89 @@ 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);
+
+ std::vector<wchar_t> full(MAX_PATH);
+ 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.empty())
return Status();
+ AutoHandle snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));
+ if (!snapshot.IsValid())
+ return Status(::GetLastError(), eErrorTypeWin32);
+
AutoHandle process(::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, GetID()),
nullptr);
if (!process.IsValid())
return Status(::GetLastError(), eErrorTypeWin32);
- std::vector<HMODULE> modules(256);
- DWORD bytes_needed = 0;
- while (true) {
- if (!::EnumProcessModulesEx(
- process.get(), modules.data(),
- static_cast<DWORD>(modules.size() * sizeof(HMODULE)), &bytes_needed,
- LIST_MODULES_ALL))
- return Status(::GetLastError(), eErrorTypeWin32);
- size_t count = bytes_needed / sizeof(HMODULE);
- if (count <= modules.size()) {
- modules.resize(count);
- break;
- }
- modules.resize(count);
- }
-
- for (HMODULE hmod : modules) {
- std::vector<wchar_t> name(MAX_PATH);
- DWORD len = 0;
- while (name.size() <= PATHCCH_MAX_CCH) {
- len = ::GetModuleFileNameExW(process.get(), hmod, name.data(),
- static_cast<DWORD>(name.size()));
- if (len == 0 || len < name.size())
- break;
- name.resize(name.size() * 2);
- }
- if (len == 0)
- continue;
-
- std::string path;
- if (!llvm::convertWideToUTF8(std::wstring(name.data(), len), path))
- continue;
-
- MODULEINFO mi = {};
- if (!::GetModuleInformation(process.get(), hmod, &mi, sizeof(mi)))
- continue;
+ MODULEENTRY32W me;
+ me.dwSize = sizeof(MODULEENTRY32W);
+ if (::Module32FirstW(snapshot.get(), &me)) {
+ do {
+ std::string path;
+ if (!GetLoadedModulePath(process.get(), me.hModule, path))
+ continue;
- FileSpec file_spec(path);
- FileSystem::Instance().Resolve(file_spec);
- m_loaded_modules[file_spec] = reinterpret_cast<addr_t>(mi.lpBaseOfDll);
+ FileSpec file_spec(path);
+ FileSystem::Instance().Resolve(file_spec);
+ m_loaded_modules[file_spec] = reinterpret_cast<addr_t>(me.modBaseAddr);
+ } while (::Module32NextW(snapshot.get(), &me));
}
if (!m_loaded_modules.empty())
More information about the lldb-commits
mailing list