https://github.com/weliveindetail updated 
https://github.com/llvm/llvm-project/pull/183089

From 1fe7ee48fb335e52428a9f6f94618d14a669d3a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]>
Date: Mon, 23 Feb 2026 13:52:42 +0100
Subject: [PATCH 1/3] [lldb] Initial infra for SymbolLocator plugin and test

---
 .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp    |  12 ++
 .../ObjectFile/PECOFF/ObjectFilePECOFF.h      |   2 +
 .../Plugins/SymbolLocator/CMakeLists.txt      |   1 +
 .../SymbolLocator/Microsoft/CMakeLists.txt    |  20 +++
 .../Microsoft/SymbolLocatorMicrosoft.cpp      | 165 ++++++++++++++++++
 .../Microsoft/SymbolLocatorMicrosoft.h        |  47 +++++
 .../SymbolLocatorMicrosoftProperties.td       |   7 +
 .../PECOFF/SymbolVendorPECOFF.cpp             |   4 +
 lldb/test/API/microsoft_symsrv/Makefile       |   2 +
 .../microsoft_symsrv/TestMicrosoftSymSrv.py   | 142 +++++++++++++++
 lldb/test/API/microsoft_symsrv/main.c         |   5 +
 11 files changed, 407 insertions(+)
 create mode 100644 lldb/source/Plugins/SymbolLocator/Microsoft/CMakeLists.txt
 create mode 100644 
lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
 create mode 100644 
lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.h
 create mode 100644 
lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoftProperties.td
 create mode 100644 lldb/test/API/microsoft_symsrv/Makefile
 create mode 100644 lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
 create mode 100644 lldb/test/API/microsoft_symsrv/main.c

diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp 
b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index 3a17b4c46a788..c85908f7ae34b 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -1108,6 +1108,18 @@ std::optional<FileSpec> ObjectFilePECOFF::GetDebugLink() 
{
   return std::nullopt;
 }
 
+std::optional<FileSpec> ObjectFilePECOFF::GetPDBPath() {
+  if (!m_binary)
+    return std::nullopt;
+  const llvm::codeview::DebugInfo *pdb_info = nullptr;
+  llvm::StringRef pdb_file;
+  if (!m_binary->getDebugPDBInfo(pdb_info, pdb_file) && pdb_info &&
+      pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70 &&
+      !pdb_file.empty())
+    return FileSpec(pdb_file);
+  return std::nullopt;
+}
+
 uint32_t ObjectFilePECOFF::ParseDependentModules() {
   ModuleSP module_sp(GetModule());
   if (!module_sp)
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h 
b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
index 8002e70e604bb..30bd672dc68f8 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h
@@ -130,6 +130,8 @@ class ObjectFilePECOFF : public lldb_private::ObjectFile {
   /// contains it.
   std::optional<lldb_private::FileSpec> GetDebugLink();
 
+  std::optional<lldb_private::FileSpec> GetPDBPath();
+
   uint32_t GetDependentModules(lldb_private::FileSpecList &files) override;
 
   lldb_private::Address GetEntryPointAddress() override;
diff --git a/lldb/source/Plugins/SymbolLocator/CMakeLists.txt 
b/lldb/source/Plugins/SymbolLocator/CMakeLists.txt
index 3b466f71dca58..818a2e18fe4fb 100644
--- a/lldb/source/Plugins/SymbolLocator/CMakeLists.txt
+++ b/lldb/source/Plugins/SymbolLocator/CMakeLists.txt
@@ -6,6 +6,7 @@ set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND SymbolLocator)
 # prevents an unstripped binary from being requested from the Debuginfod
 # provider.
 add_subdirectory(Debuginfod)
+add_subdirectory(Microsoft)
 add_subdirectory(Default)
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_subdirectory(DebugSymbols)
diff --git a/lldb/source/Plugins/SymbolLocator/Microsoft/CMakeLists.txt 
b/lldb/source/Plugins/SymbolLocator/Microsoft/CMakeLists.txt
new file mode 100644
index 0000000000000..a27ce8aa9978e
--- /dev/null
+++ b/lldb/source/Plugins/SymbolLocator/Microsoft/CMakeLists.txt
@@ -0,0 +1,20 @@
+lldb_tablegen(SymbolLocatorMicrosoftProperties.inc -gen-lldb-property-defs
+  SOURCE SymbolLocatorMicrosoftProperties.td
+  TARGET LLDBPluginSymbolLocatorMicrosoftPropertiesGen)
+
+lldb_tablegen(SymbolLocatorMicrosoftPropertiesEnum.inc 
-gen-lldb-property-enum-defs
+  SOURCE SymbolLocatorMicrosoftProperties.td
+  TARGET LLDBPluginSymbolLocatorMicrosoftPropertiesEnumGen)
+
+add_lldb_library(lldbPluginSymbolLocatorMicrosoft PLUGIN
+  SymbolLocatorMicrosoft.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+  )
+
+add_dependencies(lldbPluginSymbolLocatorMicrosoft
+  LLDBPluginSymbolLocatorMicrosoftPropertiesGen
+  LLDBPluginSymbolLocatorMicrosoftPropertiesEnumGen)
diff --git 
a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
new file mode 100644
index 0000000000000..b988f9c0be665
--- /dev/null
+++ b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
@@ -0,0 +1,165 @@
+//===-- SymbolLocatorMicrosoft.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolLocatorMicrosoft.h"
+
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Utility/Args.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/UUID.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(SymbolLocatorMicrosoft)
+
+namespace {
+
+#define LLDB_PROPERTIES_symbollocatormicrosoft
+#include "SymbolLocatorMicrosoftProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_symbollocatormicrosoft
+#include "SymbolLocatorMicrosoftPropertiesEnum.inc"
+};
+
+class PluginProperties : public Properties {
+public:
+  static llvm::StringRef GetSettingName() {
+    return SymbolLocatorMicrosoft::GetPluginNameStatic();
+  }
+
+  PluginProperties() {
+    m_collection_sp = 
std::make_shared<OptionValueProperties>(GetSettingName());
+    m_collection_sp->Initialize(g_symbollocatormicrosoft_properties_def);
+  }
+
+  Args GetURLs() const {
+    Args urls;
+    m_collection_sp->GetPropertyAtIndexAsArgs(ePropertySymStoreURLs, urls);
+    return urls;
+  }
+};
+
+} // namespace
+
+static PluginProperties &GetGlobalPluginProperties() {
+  static PluginProperties g_settings;
+  return g_settings;
+}
+
+SymbolLocatorMicrosoft::SymbolLocatorMicrosoft() : SymbolLocator() {}
+
+void SymbolLocatorMicrosoft::Initialize() {
+  static llvm::once_flag g_once_flag;
+
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(
+        GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
+        nullptr, LocateExecutableSymbolFile, nullptr,
+        nullptr, SymbolLocatorMicrosoft::DebuggerInitialize);
+  });
+}
+
+void SymbolLocatorMicrosoft::DebuggerInitialize(Debugger &debugger) {
+  if (!PluginManager::GetSettingForSymbolLocatorPlugin(
+          debugger, PluginProperties::GetSettingName())) {
+    const bool is_global_setting = true;
+    PluginManager::CreateSettingForSymbolLocatorPlugin(
+        debugger, GetGlobalPluginProperties().GetValueProperties(),
+        "Properties for the Microsoft Symbol Locator plug-in.",
+        is_global_setting);
+  }
+}
+
+void SymbolLocatorMicrosoft::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+llvm::StringRef SymbolLocatorMicrosoft::GetPluginDescriptionStatic() {
+  return "Symbol locator for PDB in Microsoft SymStore";
+}
+
+SymbolLocator *SymbolLocatorMicrosoft::CreateInstance() {
+  return new SymbolLocatorMicrosoft();
+}
+
+static llvm::StringRef getFileName(const ModuleSpec &module_spec,
+                                   std::string url_path) {
+  // Check if the URL path requests an executable file or a symbol file
+  bool is_executable = url_path.find("debuginfo") == std::string::npos;
+  if (is_executable)
+    return module_spec.GetFileSpec().GetFilename().GetStringRef();
+  llvm::StringRef symbol_file =
+      module_spec.GetSymbolFileSpec().GetFilename().GetStringRef();
+  // Remove llvmcache- prefix and hash, keep origin file name
+  if (symbol_file.starts_with("llvmcache-")) {
+    size_t pos = symbol_file.rfind('-');
+    if (pos != llvm::StringRef::npos) {
+      symbol_file = symbol_file.substr(pos + 1);
+    }
+  }
+  return symbol_file;
+}
+
+// LLDB stores PDB identity as a 20-byte UUID:
+//   bytes  0-15  GUID in big-endian canonical form
+//   bytes 16-19  Age as big-endian uint32
+//
+// The symsrv key is: <GUID-uppercase-hex><decimal-age>
+// e.g. "A0586BA32F284960B536A424603C76891" (age 1)
+static std::string formatSymStoreKey(const UUID &uuid) {
+  llvm::ArrayRef<uint8_t> bytes = uuid.GetBytes();
+  uint32_t age = llvm::support::endian::read32be(bytes.data() + 16);
+  constexpr bool LowerCase = false;
+  return llvm::toHex(bytes.slice(0, 16), LowerCase) + std::to_string(age);
+}
+
+std::optional<FileSpec> SymbolLocatorMicrosoft::LocateExecutableSymbolFile(
+    const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
+  // Bail out if we don't have a valid UUID for PDB or
+  // 'symbols.enable-external-lookup' is disabled
+  const UUID &module_uuid = module_spec.GetUUID();
+  if (!module_uuid.IsValid() || module_uuid.GetBytes().size() != 20 ||
+      !ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup())
+    return {};
+
+  Log *log = GetLog(LLDBLog::Symbols);
+
+  std::string key = formatSymStoreKey(module_uuid);
+  llvm::StringRef pdb_name =
+      module_spec.GetSymbolFileSpec().GetFilename().GetStringRef();
+  if (pdb_name.empty()) {
+    LLDB_LOGV(log, "Failed to resolve symbol PDB module: PDB name empty");
+    return {};
+  }
+
+  llvm::StringRef src_dir = 
GetGlobalPluginProperties().GetURLs().entries().front().ref();
+  Args SymStoreURLs = GetGlobalPluginProperties().GetURLs();
+  for (const Args::ArgEntry &URL : SymStoreURLs) {
+    llvm::SmallString<256> src;
+    llvm::sys::path::append(src, src_dir, pdb_name, URL.ref(), pdb_name);
+    FileSpec src_spec(src);
+    if (!FileSystem::Instance().Exists(src_spec)) {
+      LLDB_LOGV(log, "SymbolLocatorMicrosoft: {0} not found in symstore", src);
+      continue;
+    }
+    return src_spec;
+  }
+
+  return {};
+}
diff --git 
a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.h 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.h
new file mode 100644
index 0000000000000..36bdfd4d67d9a
--- /dev/null
+++ b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.h
@@ -0,0 +1,47 @@
+//===-- SymbolLocatorMicrosoft.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_MICROSOFT_SYMBOLLOCATORMICROSOFT_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_MICROSOFT_SYMBOLLOCATORMICROSOFT_H
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Symbol/SymbolLocator.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class SymbolLocatorMicrosoft : public SymbolLocator {
+public:
+  SymbolLocatorMicrosoft();
+
+  static void Initialize();
+  static void Terminate();
+  static void DebuggerInitialize(Debugger &debugger);
+
+  static llvm::StringRef GetPluginNameStatic() { return "microsoft"; }
+  static llvm::StringRef GetPluginDescriptionStatic();
+
+  static lldb_private::SymbolLocator *CreateInstance();
+
+  /// PluginInterface protocol.
+  /// \{
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+  /// \}
+
+  // Locate the symbol file given a module specification.
+  //
+  // Locating the file should happen only on the local computer or using the
+  // current computers global settings.
+  static std::optional<FileSpec>
+  LocateExecutableSymbolFile(const ModuleSpec &module_spec,
+                             const FileSpecList &default_search_paths);
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_MICROSOFT_SYMBOLLOCATORMICROSOFT_H
diff --git 
a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoftProperties.td
 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoftProperties.td
new file mode 100644
index 0000000000000..d02098536689d
--- /dev/null
+++ 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoftProperties.td
@@ -0,0 +1,7 @@
+include "../../../../include/lldb/Core/PropertiesBase.td"
+
+let Definition = "symbollocatormicrosoft", Path = 
"plugin.symbol-locator.microsoft" in {
+  def SymStoreURLs : Property<"symstore-urls", "Array">,
+    ElementType<"String">,
+    Desc<"An ordered list of symstore URLs to query for symbols. This is 
prepended to the contents of the _NT_SYMBOL_PATH environment variable.">;
+}
diff --git a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp 
b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
index 20ccfa54a106c..1f23620372db3 100644
--- a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
+++ b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
@@ -74,6 +74,10 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP 
&module_sp,
   // Otherwise, try gnu_debuglink, if one exists.
   if (!fspec)
     fspec = obj_file->GetDebugLink().value_or(FileSpec());
+  // For MSVC PE files, fall back to the PDB path from the CodeView debug
+  // directory so that symbol locators can use the filename for server lookups.
+  if (!fspec)
+    fspec = obj_file->GetPDBPath().value_or(FileSpec());
 
   LLDB_SCOPED_TIMERF("SymbolVendorPECOFF::CreateInstance (module = %s)",
                      module_sp->GetFileSpec().GetPath().c_str());
diff --git a/lldb/test/API/microsoft_symsrv/Makefile 
b/lldb/test/API/microsoft_symsrv/Makefile
new file mode 100644
index 0000000000000..c9319d6e6888a
--- /dev/null
+++ b/lldb/test/API/microsoft_symsrv/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git a/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py 
b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
new file mode 100644
index 0000000000000..4e778362ba713
--- /dev/null
+++ b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
@@ -0,0 +1,142 @@
+import glob
+import os
+import shutil
+import tempfile
+
+import lldb
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+
+"""
+Test support for the Microsoft symbol server (symsrv) protocol.
+
+LLDB's SymbolLocatorMicrosoft plugin locates PDB files from symbol servers
+that follow the Microsoft symsrv directory layout:
+
+  <store>/<pdb-name>/<GUID-uppercase-no-dashes><age-decimal>/<pdb-name>
+
+The symstore-urls setting accepts entries in SRV*<cache>*<server> notation,
+matching the _NT_SYMBOL_PATH convention used by WinDbg and other Microsoft
+debuggers.
+"""
+
+import debugpy
+debugpy.listen(("127.0.0.1", 5678))
+debugpy.wait_for_client()
+debugpy.breakpoint()
+
+class MicrosoftSymSrvTests(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessPlatform(["windows"])
+    def test_local_folder(self):
+        """Verify that LLDB fetches the PDB from a local SymStore directory."""
+        tmp_dir = tempfile.mkdtemp()
+        symstore_dir = self.populate_symstore(tmp_dir)
+        
+        self.runCmd(
+            "settings set plugin.symbol-locator.microsoft.symstore-urls %s" %
+            symstore_dir.replace("\\", "/")
+        )
+
+        self.try_breakpoint(should_have_loc=True)
+        #shutil.rmtree(tmp_dir)
+        print(tmp_dir)
+
+    def try_breakpoint(self, should_have_loc):
+        target = self.dbg.CreateTarget(self.aout)
+        self.assertTrue(target and target.IsValid(), "Target is valid")
+
+        bp = target.BreakpointCreateByName("func")
+        self.assertTrue(bp and bp.IsValid(), "Breakpoint is valid")
+        self.assertEqual(bp.GetNumLocations(), 1)
+
+        loc = bp.GetLocationAtIndex(0)
+        self.assertTrue(loc and loc.IsValid(), "Location is valid")
+        addr = loc.GetAddress()
+        self.assertTrue(addr and addr.IsValid(), "Loc address is valid")
+        line_entry = addr.GetLineEntry()
+        self.assertEqual(
+            should_have_loc,
+            line_entry is not None and line_entry.IsValid(),
+            "Loc line entry validity",
+        )
+        if should_have_loc:
+            self.assertEqual(line_entry.GetLine(), 2)
+            self.assertEqual(
+                line_entry.GetFileSpec().GetFilename(),
+                self.main_source_file.GetFilename(),
+            )
+        self.dbg.DeleteTarget(target)
+
+    def populate_symstore(self, tmp):
+        """
+        Build test binary, mock local symstore directory tree:
+          tmp/test/a.out                 binary (no PDB in search path)
+          tmp/server/<pdb>/<key>/<pdb>   PDB in symstore
+        """
+        self.build()
+        pdbs = glob.glob(os.path.join(self.getBuildDir(), "*.pdb"))
+        if len(pdbs) == 0:
+            self.skipTest("Build did not produce a PDB file")
+
+        self.main_source_file = lldb.SBFileSpec("main.c")
+
+        binary_name = "a.out"
+        pdb_name = "a.pdb"
+        uuid_str = self._get_uuid(binary_name)
+        if uuid_str is None:
+            self.skipTest("Could not obtain a 20-byte PDB UUID from the 
binary")
+
+        symsrv_key = self._uuid_to_symsrv_key(uuid_str)
+
+        # Set up test directory with just the binary (no PDB).
+        test_dir = os.path.join(tmp, "test")
+        os.makedirs(test_dir)
+        shutil.move(self.getBuildArtifact(binary_name), test_dir)
+        self.aout = os.path.join(test_dir, binary_name)
+
+        # SymStore directory tree: <pdb>/<key>/<pdb>
+        server_dir = os.path.join(tmp, "server")
+        pdb_key_dir = os.path.join(server_dir, pdb_name, symsrv_key)
+        os.makedirs(pdb_key_dir)
+        shutil.move(
+            self.getBuildArtifact(pdb_name),
+            os.path.join(pdb_key_dir, pdb_name),
+        )
+
+        return server_dir
+
+    # -----------------------------------------------------------------------
+    # Private helpers
+    # -----------------------------------------------------------------------
+
+    #def _get_pdb_name(self):
+    #    """Return the basename of the first PDB in the build directory."""
+    #    pdbs = glob.glob(os.path.join(self.getBuildDir(), "*.pdb"))
+    #    return os.path.basename(pdbs[0]) if pdbs else None
+
+    def _get_uuid(self, binary_name):
+        """Return the UUID string (dashes removed, lowercase) for binary_name,
+        or None if it is not a 20-byte PDB UUID."""
+        try:
+            spec = lldb.SBModuleSpec()
+            spec.SetFileSpec(
+                lldb.SBFileSpec(self.getBuildArtifact(binary_name))
+            )
+            module = lldb.SBModule(spec)
+            raw = module.GetUUIDString().replace("-", "").lower()
+            return raw if len(raw) == 40 else None
+        except Exception:
+            return None
+
+    @staticmethod
+    def _uuid_to_symsrv_key(uuid_lower_40):
+        """Convert a 40-char lowercase hex UUID string to a Microsoft symsrv
+        key: uppercase GUID (32 chars) followed by decimal age."""
+        upper = uuid_lower_40.upper()
+        guid_hex = upper[:32]
+        age = int(upper[32:], 16)
+        return guid_hex + str(age)
diff --git a/lldb/test/API/microsoft_symsrv/main.c 
b/lldb/test/API/microsoft_symsrv/main.c
new file mode 100644
index 0000000000000..a95762e80ea44
--- /dev/null
+++ b/lldb/test/API/microsoft_symsrv/main.c
@@ -0,0 +1,5 @@
+int func(int argc, const char *argv[]) {
+  return (argc + 1) * (argv[argc][0] + 2);
+}
+
+int main(int argc, const char *argv[]) { return func(0, argv); }

From add842d809b902e85b4d6cc2daad2517282761d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]>
Date: Tue, 24 Feb 2026 16:15:00 +0100
Subject: [PATCH 2/3] Polish symbol locator plugin and test

---
 .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp    | 19 ++--
 .../Microsoft/SymbolLocatorMicrosoft.cpp      | 91 ++++++++----------
 .../PECOFF/SymbolVendorPECOFF.cpp             |  7 +-
 .../microsoft_symsrv/TestMicrosoftSymSrv.py   | 94 ++++++-------------
 4 files changed, 83 insertions(+), 128 deletions(-)

diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp 
b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index c85908f7ae34b..2e169bb6e8a53 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -1109,15 +1109,18 @@ std::optional<FileSpec> 
ObjectFilePECOFF::GetDebugLink() {
 }
 
 std::optional<FileSpec> ObjectFilePECOFF::GetPDBPath() {
-  if (!m_binary)
-    return std::nullopt;
-  const llvm::codeview::DebugInfo *pdb_info = nullptr;
   llvm::StringRef pdb_file;
-  if (!m_binary->getDebugPDBInfo(pdb_info, pdb_file) && pdb_info &&
-      pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70 &&
-      !pdb_file.empty())
-    return FileSpec(pdb_file);
-  return std::nullopt;
+  const llvm::codeview::DebugInfo *pdb_info = nullptr;
+  if (llvm::Error Err = m_binary->getDebugPDBInfo(pdb_info, pdb_file)) {
+    // Ignore corrupt DebugInfo sections
+    llvm::consumeError(std::move(Err));
+    return std::nullopt;
+  }
+  if (pdb_file.empty()) {
+    // No DebugInfo section
+    return std::nullopt;
+  }
+  return FileSpec(pdb_file);
 }
 
 uint32_t ObjectFilePECOFF::ParseDependentModules() {
diff --git 
a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
index b988f9c0be665..549460df97d02 100644
--- a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
+++ b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
@@ -65,20 +65,17 @@ static PluginProperties &GetGlobalPluginProperties() {
 SymbolLocatorMicrosoft::SymbolLocatorMicrosoft() : SymbolLocator() {}
 
 void SymbolLocatorMicrosoft::Initialize() {
-  static llvm::once_flag g_once_flag;
-
-  llvm::call_once(g_once_flag, []() {
-    PluginManager::RegisterPlugin(
-        GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
-        nullptr, LocateExecutableSymbolFile, nullptr,
-        nullptr, SymbolLocatorMicrosoft::DebuggerInitialize);
-  });
+  // First version can only locate PDB in local SymStore (no download yet)
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
+      nullptr, LocateExecutableSymbolFile, nullptr,
+      nullptr, SymbolLocatorMicrosoft::DebuggerInitialize);
 }
 
 void SymbolLocatorMicrosoft::DebuggerInitialize(Debugger &debugger) {
   if (!PluginManager::GetSettingForSymbolLocatorPlugin(
           debugger, PluginProperties::GetSettingName())) {
-    const bool is_global_setting = true;
+    constexpr bool is_global_setting = true;
     PluginManager::CreateSettingForSymbolLocatorPlugin(
         debugger, GetGlobalPluginProperties().GetValueProperties(),
         "Properties for the Microsoft Symbol Locator plug-in.",
@@ -98,30 +95,13 @@ SymbolLocator *SymbolLocatorMicrosoft::CreateInstance() {
   return new SymbolLocatorMicrosoft();
 }
 
-static llvm::StringRef getFileName(const ModuleSpec &module_spec,
-                                   std::string url_path) {
-  // Check if the URL path requests an executable file or a symbol file
-  bool is_executable = url_path.find("debuginfo") == std::string::npos;
-  if (is_executable)
-    return module_spec.GetFileSpec().GetFilename().GetStringRef();
-  llvm::StringRef symbol_file =
-      module_spec.GetSymbolFileSpec().GetFilename().GetStringRef();
-  // Remove llvmcache- prefix and hash, keep origin file name
-  if (symbol_file.starts_with("llvmcache-")) {
-    size_t pos = symbol_file.rfind('-');
-    if (pos != llvm::StringRef::npos) {
-      symbol_file = symbol_file.substr(pos + 1);
-    }
-  }
-  return symbol_file;
-}
-
-// LLDB stores PDB identity as a 20-byte UUID:
-//   bytes  0-15  GUID in big-endian canonical form
-//   bytes 16-19  Age as big-endian uint32
+// LLDB stores PDB identity as a 20-byte UUID composed of 16-byte GUID and
+// 4-byte age:
+//   12345678-1234-5678-9ABC-DEF012345678-00000001
+//
+// SymStore key is a string with no separators and age as decimal:
+//   12345678123456789ABCDEF0123456781
 //
-// The symsrv key is: <GUID-uppercase-hex><decimal-age>
-// e.g. "A0586BA32F284960B536A424603C76891" (age 1)
 static std::string formatSymStoreKey(const UUID &uuid) {
   llvm::ArrayRef<uint8_t> bytes = uuid.GetBytes();
   uint32_t age = llvm::support::endian::read32be(bytes.data() + 16);
@@ -131,34 +111,45 @@ static std::string formatSymStoreKey(const UUID &uuid) {
 
 std::optional<FileSpec> SymbolLocatorMicrosoft::LocateExecutableSymbolFile(
     const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
-  // Bail out if we don't have a valid UUID for PDB or
-  // 'symbols.enable-external-lookup' is disabled
-  const UUID &module_uuid = module_spec.GetUUID();
-  if (!module_uuid.IsValid() || module_uuid.GetBytes().size() != 20 ||
+  const UUID &uuid = module_spec.GetUUID();
+  if (!uuid.IsValid() ||
       !ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup())
     return {};
 
   Log *log = GetLog(LLDBLog::Symbols);
-
-  std::string key = formatSymStoreKey(module_uuid);
-  llvm::StringRef pdb_name =
-      module_spec.GetSymbolFileSpec().GetFilename().GetStringRef();
+  std::string pdb_name =
+      module_spec.GetSymbolFileSpec().GetFilename().GetStringRef().str();
   if (pdb_name.empty()) {
     LLDB_LOGV(log, "Failed to resolve symbol PDB module: PDB name empty");
     return {};
   }
 
-  llvm::StringRef src_dir = 
GetGlobalPluginProperties().GetURLs().entries().front().ref();
-  Args SymStoreURLs = GetGlobalPluginProperties().GetURLs();
-  for (const Args::ArgEntry &URL : SymStoreURLs) {
-    llvm::SmallString<256> src;
-    llvm::sys::path::append(src, src_dir, pdb_name, URL.ref(), pdb_name);
-    FileSpec src_spec(src);
-    if (!FileSystem::Instance().Exists(src_spec)) {
-      LLDB_LOGV(log, "SymbolLocatorMicrosoft: {0} not found in symstore", src);
-      continue;
+  LLDB_LOGV(log, "LocateExecutableSymbolFile {0} with UUID {1}", pdb_name,
+            uuid.GetAsString());
+  if (uuid.GetBytes().size() != 20) {
+    LLDB_LOGV(log, "  Failed to resolve symbol PDB module: UUID invalid");
+    return {};
+  }
+
+  // FIXME: We need this for the test executable, because it is loaded as DWARF
+  if (!llvm::StringRef(pdb_name).ends_with(".pdb")) {
+    auto last_dot = pdb_name.find_last_of('.');
+    if (last_dot != llvm::StringRef::npos) {
+      pdb_name = pdb_name.substr(0, last_dot);
+    }
+    pdb_name += ".pdb";
+  }
+
+  std::string key = formatSymStoreKey(uuid);
+  Args sym_store_urls = GetGlobalPluginProperties().GetURLs();
+  for (const Args::ArgEntry &url : sym_store_urls) {
+    llvm::SmallString<256> path;
+    llvm::sys::path::append(path, url.ref(), pdb_name, key, pdb_name);
+    FileSpec spec(path);
+    if (FileSystem::Instance().Exists(spec)) {
+      LLDB_LOGV(log, "  Found {0} in SymStore {1}", pdb_name, url.ref());
+      return spec;
     }
-    return src_spec;
   }
 
   return {};
diff --git a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp 
b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
index 1f23620372db3..94c3548b80e4a 100644
--- a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
+++ b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
@@ -71,13 +71,12 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP 
&module_sp,
 
   // If the module specified a filespec, use that.
   FileSpec fspec = module_sp->GetSymbolFileFileSpec();
+  // Otherwise, use the PDB path from CodeView.
+  if (!fspec)
+    fspec = obj_file->GetPDBPath().value_or(FileSpec());
   // Otherwise, try gnu_debuglink, if one exists.
   if (!fspec)
     fspec = obj_file->GetDebugLink().value_or(FileSpec());
-  // For MSVC PE files, fall back to the PDB path from the CodeView debug
-  // directory so that symbol locators can use the filename for server lookups.
-  if (!fspec)
-    fspec = obj_file->GetPDBPath().value_or(FileSpec());
 
   LLDB_SCOPED_TIMERF("SymbolVendorPECOFF::CreateInstance (module = %s)",
                      module_sp->GetFileSpec().GetPath().c_str());
diff --git a/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py 
b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
index 4e778362ba713..eaae4792489f0 100644
--- a/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
+++ b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
@@ -5,46 +5,11 @@
 
 import lldb
 from lldbsuite.test.decorators import *
-import lldbsuite.test.lldbutil as lldbutil
 from lldbsuite.test.lldbtest import *
 
-
-"""
-Test support for the Microsoft symbol server (symsrv) protocol.
-
-LLDB's SymbolLocatorMicrosoft plugin locates PDB files from symbol servers
-that follow the Microsoft symsrv directory layout:
-
-  <store>/<pdb-name>/<GUID-uppercase-no-dashes><age-decimal>/<pdb-name>
-
-The symstore-urls setting accepts entries in SRV*<cache>*<server> notation,
-matching the _NT_SYMBOL_PATH convention used by WinDbg and other Microsoft
-debuggers.
-"""
-
-import debugpy
-debugpy.listen(("127.0.0.1", 5678))
-debugpy.wait_for_client()
-debugpy.breakpoint()
-
 class MicrosoftSymSrvTests(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
-    @skipUnlessPlatform(["windows"])
-    def test_local_folder(self):
-        """Verify that LLDB fetches the PDB from a local SymStore directory."""
-        tmp_dir = tempfile.mkdtemp()
-        symstore_dir = self.populate_symstore(tmp_dir)
-        
-        self.runCmd(
-            "settings set plugin.symbol-locator.microsoft.symstore-urls %s" %
-            symstore_dir.replace("\\", "/")
-        )
-
-        self.try_breakpoint(should_have_loc=True)
-        #shutil.rmtree(tmp_dir)
-        print(tmp_dir)
-
     def try_breakpoint(self, should_have_loc):
         target = self.dbg.CreateTarget(self.aout)
         self.assertTrue(target and target.IsValid(), "Target is valid")
@@ -73,7 +38,7 @@ def try_breakpoint(self, should_have_loc):
 
     def populate_symstore(self, tmp):
         """
-        Build test binary, mock local symstore directory tree:
+        Build test binary and mock local symstore directory tree:
           tmp/test/a.out                 binary (no PDB in search path)
           tmp/server/<pdb>/<key>/<pdb>   PDB in symstore
         """
@@ -86,12 +51,10 @@ def populate_symstore(self, tmp):
 
         binary_name = "a.out"
         pdb_name = "a.pdb"
-        uuid_str = self._get_uuid(binary_name)
-        if uuid_str is None:
+        key = self.symstore_key(binary_name)
+        if key is None:
             self.skipTest("Could not obtain a 20-byte PDB UUID from the 
binary")
 
-        symsrv_key = self._uuid_to_symsrv_key(uuid_str)
-
         # Set up test directory with just the binary (no PDB).
         test_dir = os.path.join(tmp, "test")
         os.makedirs(test_dir)
@@ -100,7 +63,7 @@ def populate_symstore(self, tmp):
 
         # SymStore directory tree: <pdb>/<key>/<pdb>
         server_dir = os.path.join(tmp, "server")
-        pdb_key_dir = os.path.join(server_dir, pdb_name, symsrv_key)
+        pdb_key_dir = os.path.join(server_dir, pdb_name, key)
         os.makedirs(pdb_key_dir)
         shutil.move(
             self.getBuildArtifact(pdb_name),
@@ -109,34 +72,33 @@ def populate_symstore(self, tmp):
 
         return server_dir
 
-    # -----------------------------------------------------------------------
-    # Private helpers
-    # -----------------------------------------------------------------------
-
-    #def _get_pdb_name(self):
-    #    """Return the basename of the first PDB in the build directory."""
-    #    pdbs = glob.glob(os.path.join(self.getBuildDir(), "*.pdb"))
-    #    return os.path.basename(pdbs[0]) if pdbs else None
-
-    def _get_uuid(self, binary_name):
-        """Return the UUID string (dashes removed, lowercase) for binary_name,
-        or None if it is not a 20-byte PDB UUID."""
+    def symstore_key(self, exe):
+        """Load module UUID like: 12345678-1234-5678-9ABC-DEF012345678-00000001
+           and transform to SymStore key: 12345678123456789ABCDEF0123456781"""
         try:
             spec = lldb.SBModuleSpec()
-            spec.SetFileSpec(
-                lldb.SBFileSpec(self.getBuildArtifact(binary_name))
-            )
+            spec.SetFileSpec(lldb.SBFileSpec(self.getBuildArtifact(exe)))
             module = lldb.SBModule(spec)
-            raw = module.GetUUIDString().replace("-", "").lower()
-            return raw if len(raw) == 40 else None
+            raw = module.GetUUIDString().replace("-", "").upper()
+            if len(raw) != 40:
+                return None
+            guid_hex = raw[:32]
+            age = int(raw[32:], 16)
+            return guid_hex + str(age)
         except Exception:
             return None
 
-    @staticmethod
-    def _uuid_to_symsrv_key(uuid_lower_40):
-        """Convert a 40-char lowercase hex UUID string to a Microsoft symsrv
-        key: uppercase GUID (32 chars) followed by decimal age."""
-        upper = uuid_lower_40.upper()
-        guid_hex = upper[:32]
-        age = int(upper[32:], 16)
-        return guid_hex + str(age)
+    # TODO: Check on other platforms, it should work in theory
+    @skipUnlessPlatform(["windows"])
+    def test_local_folder(self):
+        """Check that LLDB can fetch PDB from local SymStore directory"""
+        tmp_dir = tempfile.mkdtemp()
+        symstore_dir = self.populate_symstore(tmp_dir)
+        
+        self.runCmd(
+            "settings set plugin.symbol-locator.microsoft.symstore-urls %s" %
+            symstore_dir.replace("\\", "/")
+        )
+
+        self.try_breakpoint(should_have_loc=True)
+        shutil.rmtree(tmp_dir)

From 4a9bec246bb435564b9bb0711e0f20fb4724287e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]>
Date: Tue, 24 Feb 2026 17:11:05 +0100
Subject: [PATCH 3/3] Fix formatting (NFC)

---
 .../SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp   | 4 ++--
 lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py    | 9 +++++----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git 
a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp 
b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
index 549460df97d02..9d8a018639673 100644
--- a/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
+++ b/lldb/source/Plugins/SymbolLocator/Microsoft/SymbolLocatorMicrosoft.cpp
@@ -68,8 +68,8 @@ void SymbolLocatorMicrosoft::Initialize() {
   // First version can only locate PDB in local SymStore (no download yet)
   PluginManager::RegisterPlugin(
       GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
-      nullptr, LocateExecutableSymbolFile, nullptr,
-      nullptr, SymbolLocatorMicrosoft::DebuggerInitialize);
+      nullptr, LocateExecutableSymbolFile, nullptr, nullptr,
+      SymbolLocatorMicrosoft::DebuggerInitialize);
 }
 
 void SymbolLocatorMicrosoft::DebuggerInitialize(Debugger &debugger) {
diff --git a/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py 
b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
index eaae4792489f0..f69d4cc9791be 100644
--- a/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
+++ b/lldb/test/API/microsoft_symsrv/TestMicrosoftSymSrv.py
@@ -7,6 +7,7 @@
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
 
+
 class MicrosoftSymSrvTests(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
@@ -74,7 +75,7 @@ def populate_symstore(self, tmp):
 
     def symstore_key(self, exe):
         """Load module UUID like: 12345678-1234-5678-9ABC-DEF012345678-00000001
-           and transform to SymStore key: 12345678123456789ABCDEF0123456781"""
+        and transform to SymStore key: 12345678123456789ABCDEF0123456781"""
         try:
             spec = lldb.SBModuleSpec()
             spec.SetFileSpec(lldb.SBFileSpec(self.getBuildArtifact(exe)))
@@ -94,10 +95,10 @@ def test_local_folder(self):
         """Check that LLDB can fetch PDB from local SymStore directory"""
         tmp_dir = tempfile.mkdtemp()
         symstore_dir = self.populate_symstore(tmp_dir)
-        
+
         self.runCmd(
-            "settings set plugin.symbol-locator.microsoft.symstore-urls %s" %
-            symstore_dir.replace("\\", "/")
+            "settings set plugin.symbol-locator.microsoft.symstore-urls %s"
+            % symstore_dir.replace("\\", "/")
         )
 
         self.try_breakpoint(should_have_loc=True)

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to