https://github.com/weliveindetail updated https://github.com/llvm/llvm-project/pull/185658
From 069d77c58181e8e9dde30b97434bcbd97e6ff40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Tue, 10 Mar 2026 13:43:53 +0100 Subject: [PATCH 1/8] Reland "[lldb] Initial plugin and test for SymbolLocatorSymStore" --- .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 21 +++ .../ObjectFile/PECOFF/ObjectFilePECOFF.h | 2 + .../Plugins/SymbolLocator/CMakeLists.txt | 1 + .../SymbolLocator/SymStore/CMakeLists.txt | 20 +++ .../SymStore/SymbolLocatorSymStore.cpp | 147 ++++++++++++++++++ .../SymStore/SymbolLocatorSymStore.h | 50 ++++++ .../SymbolLocatorSymStoreProperties.td | 7 + .../PECOFF/SymbolVendorPECOFF.cpp | 48 +++--- lldb/test/API/symstore/Makefile | 2 + lldb/test/API/symstore/TestSymStoreLocal.py | 121 ++++++++++++++ lldb/test/API/symstore/main.c | 5 + 11 files changed, 401 insertions(+), 23 deletions(-) create mode 100644 lldb/source/Plugins/SymbolLocator/SymStore/CMakeLists.txt create mode 100644 lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.cpp create mode 100644 lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.h create mode 100644 lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStoreProperties.td create mode 100644 lldb/test/API/symstore/Makefile create mode 100644 lldb/test/API/symstore/TestSymStoreLocal.py create mode 100644 lldb/test/API/symstore/main.c diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 3a17b4c46a788..cec47d96b33d2 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -1108,6 +1108,27 @@ std::optional<FileSpec> ObjectFilePECOFF::GetDebugLink() { return std::nullopt; } +std::optional<FileSpec> ObjectFilePECOFF::GetPDBPath() { + llvm::StringRef pdb_file; + const llvm::codeview::DebugInfo *pdb_info = nullptr; + if (llvm::Error Err = m_binary->getDebugPDBInfo(pdb_info, pdb_file)) { + // DebugInfo section is corrupt. + Log *log = GetLog(LLDBLog::Object); + llvm::StringRef file = m_binary->getFileName(); + LLDB_LOG_ERROR( + log, std::move(Err), + "Failed to read Codeview record for PDB debug info file ({1}): {0}", + file); + return std::nullopt; + } + if (pdb_file.empty()) { + // No DebugInfo section present. + return std::nullopt; + } + return FileSpec(pdb_file, FileSpec::GuessPathStyle(pdb_file).value_or( + FileSpec::Style::native)); +} + 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..9b9ec470b86a9 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(SymStore) add_subdirectory(Default) if (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(DebugSymbols) diff --git a/lldb/source/Plugins/SymbolLocator/SymStore/CMakeLists.txt b/lldb/source/Plugins/SymbolLocator/SymStore/CMakeLists.txt new file mode 100644 index 0000000000000..b0da27f26c6a8 --- /dev/null +++ b/lldb/source/Plugins/SymbolLocator/SymStore/CMakeLists.txt @@ -0,0 +1,20 @@ +lldb_tablegen(SymbolLocatorSymStoreProperties.inc -gen-lldb-property-defs + SOURCE SymbolLocatorSymStoreProperties.td + TARGET LLDBPluginSymbolLocatorSymStorePropertiesGen) + +lldb_tablegen(SymbolLocatorSymStorePropertiesEnum.inc -gen-lldb-property-enum-defs + SOURCE SymbolLocatorSymStoreProperties.td + TARGET LLDBPluginSymbolLocatorSymStorePropertiesEnumGen) + +add_lldb_library(lldbPluginSymbolLocatorSymStore PLUGIN + SymbolLocatorSymStore.cpp + + LINK_LIBS + lldbCore + lldbHost + lldbSymbol + ) + +add_dependencies(lldbPluginSymbolLocatorSymStore + LLDBPluginSymbolLocatorSymStorePropertiesGen + LLDBPluginSymbolLocatorSymStorePropertiesEnumGen) diff --git a/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.cpp b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.cpp new file mode 100644 index 0000000000000..d008a7d3e8e9a --- /dev/null +++ b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.cpp @@ -0,0 +1,147 @@ +//===----------------------------------------------------------------------===// +// +// 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 "SymbolLocatorSymStore.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(SymbolLocatorSymStore) + +namespace { + +#define LLDB_PROPERTIES_symbollocatorsymstore +#include "SymbolLocatorSymStoreProperties.inc" + +enum { +#define LLDB_PROPERTIES_symbollocatorsymstore +#include "SymbolLocatorSymStorePropertiesEnum.inc" +}; + +class PluginProperties : public Properties { +public: + static llvm::StringRef GetSettingName() { + return SymbolLocatorSymStore::GetPluginNameStatic(); + } + + PluginProperties() { + m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); + m_collection_sp->Initialize(g_symbollocatorsymstore_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; +} + +SymbolLocatorSymStore::SymbolLocatorSymStore() : SymbolLocator() {} + +void SymbolLocatorSymStore::Initialize() { + // First version can only locate PDB in local SymStore (no download yet). + PluginManager::RegisterPlugin( + GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, + nullptr, LocateExecutableSymbolFile, nullptr, nullptr, + SymbolLocatorSymStore::DebuggerInitialize); +} + +void SymbolLocatorSymStore::DebuggerInitialize(Debugger &debugger) { + if (!PluginManager::GetSettingForSymbolLocatorPlugin( + debugger, PluginProperties::GetSettingName())) { + constexpr bool is_global_setting = true; + PluginManager::CreateSettingForSymbolLocatorPlugin( + debugger, GetGlobalPluginProperties().GetValueProperties(), + "Properties for the SymStore Symbol Locator plug-in.", + is_global_setting); + } +} + +void SymbolLocatorSymStore::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef SymbolLocatorSymStore::GetPluginDescriptionStatic() { + return "Symbol locator for PDB in SymStore"; +} + +SymbolLocator *SymbolLocatorSymStore::CreateInstance() { + return new SymbolLocatorSymStore(); +} + +// RSDS entries store 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 +// +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> SymbolLocatorSymStore::LocateExecutableSymbolFile( + const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { + const UUID &uuid = module_spec.GetUUID(); + if (!uuid.IsValid() || + !ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) + return {}; + + Log *log = GetLog(LLDBLog::Symbols); + 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 {}; + } + + 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 {}; + } + + 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 {}; +} diff --git a/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.h b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.h new file mode 100644 index 0000000000000..52ec04cae387b --- /dev/null +++ b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStore.h @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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_SYMSTORE_SYMBOLLOCATORSYMSTORE_H +#define LLDB_SOURCE_PLUGINS_SYMBOLLOCATOR_SYMSTORE_SYMBOLLOCATORSYMSTORE_H + +#include "lldb/Core/Debugger.h" +#include "lldb/Symbol/SymbolLocator.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +/// This plugin implements lookup in Microsoft SymStore instances. This can work +/// cross-platform and for arbitrary debug info formats, but the focus is on PDB +/// with PE/COFF binaries on Windows. +class SymbolLocatorSymStore : public SymbolLocator { +public: + SymbolLocatorSymStore(); + + static void Initialize(); + static void Terminate(); + static void DebuggerInitialize(Debugger &debugger); + + static llvm::StringRef GetPluginNameStatic() { return "symstore"; } + 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_SYMSTORE_SYMBOLLOCATORSYMSTORE_H diff --git a/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStoreProperties.td b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStoreProperties.td new file mode 100644 index 0000000000000..0cd631a80b90b --- /dev/null +++ b/lldb/source/Plugins/SymbolLocator/SymStore/SymbolLocatorSymStoreProperties.td @@ -0,0 +1,7 @@ +include "../../../../include/lldb/Core/PropertiesBase.td" + +let Definition = "symbollocatorsymstore", Path = "plugin.symbol-locator.symstore" in { + def SymStoreURLs : Property<"urls", "Array">, + ElementType<"String">, + Desc<"List of local symstore directories to query for symbols">; +} diff --git a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp index 20ccfa54a106c..1797e5b7677ee 100644 --- a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp +++ b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp @@ -71,6 +71,9 @@ 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()); @@ -101,31 +104,30 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp, // This objfile is for debugging purposes. dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo); - // Get the module unified section list and add our debug sections to - // that. + // For DWARF get the module unified section list and add our debug sections + // to that. SectionList *module_section_list = module_sp->GetSectionList(); SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList(); - if (!objfile_section_list || !module_section_list) - return nullptr; - - static const SectionType g_sections[] = { - eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAranges, - eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, - eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, - eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo, - eSectionTypeDWARFDebugNames, eSectionTypeDWARFDebugPubNames, - eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, - eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugTypes, - }; - for (SectionType section_type : g_sections) { - if (SectionSP section_sp = - objfile_section_list->FindSectionByType(section_type, true)) { - if (SectionSP module_section_sp = - module_section_list->FindSectionByType(section_type, true)) - module_section_list->ReplaceSection(module_section_sp->GetID(), - section_sp); - else - module_section_list->AddSection(section_sp); + if (objfile_section_list && module_section_list) { + static const SectionType g_sections[] = { + eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAranges, + eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, + eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, + eSectionTypeDWARFDebugLocLists, eSectionTypeDWARFDebugMacInfo, + eSectionTypeDWARFDebugNames, eSectionTypeDWARFDebugPubNames, + eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, + eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugTypes, + }; + for (SectionType section_type : g_sections) { + if (SectionSP section_sp = + objfile_section_list->FindSectionByType(section_type, true)) { + if (SectionSP module_section_sp = + module_section_list->FindSectionByType(section_type, true)) + module_section_list->ReplaceSection(module_section_sp->GetID(), + section_sp); + else + module_section_list->AddSection(section_sp); + } } } diff --git a/lldb/test/API/symstore/Makefile b/lldb/test/API/symstore/Makefile new file mode 100644 index 0000000000000..c9319d6e6888a --- /dev/null +++ b/lldb/test/API/symstore/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules diff --git a/lldb/test/API/symstore/TestSymStoreLocal.py b/lldb/test/API/symstore/TestSymStoreLocal.py new file mode 100644 index 0000000000000..154af876fea3f --- /dev/null +++ b/lldb/test/API/symstore/TestSymStoreLocal.py @@ -0,0 +1,121 @@ +import os +import shutil +import tempfile + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +""" +Test debug symbol acquisition from a local SymStore repository. This can work +cross-platform and for arbitrary debug info formats. We only support PDB +currently. +""" + + +class MockedSymStore: + """ + Context Manager to populate a file structure equivalent to SymStore.exe in a + temporary directory. + """ + + def __init__(self, test, exe, pdb): + self._test = test + self._exe = exe + self._pdb = pdb + self._tmp = None + + def get_key_pdb(self, exe): + """ + Module UUID: 12345678-1234-5678-9ABC-DEF012345678-00000001 + To SymStore key: 12345678123456789ABCDEF0123456781 + """ + spec = lldb.SBModuleSpec() + spec.SetFileSpec(lldb.SBFileSpec(self._test.getBuildArtifact(exe))) + module = lldb.SBModule(spec) + raw = module.GetUUIDString().replace("-", "").upper() + if len(raw) != 40: + raise RuntimeError("Unexpected number of bytes in embedded UUID") + guid_hex = raw[:32] + age = int(raw[32:], 16) + return guid_hex + str(age) + + def __enter__(self): + """ + Mock local symstore directory tree, move PDB there and report path. + """ + key = None + if self._test.getDebugInfo() == "pdb": + key = self.get_key_pdb(self._exe) + self._test.assertIsNotNone(key) + self._tmp = tempfile.mkdtemp() + pdb_dir = os.path.join(self._tmp, self._pdb, key) + os.makedirs(pdb_dir) + shutil.move( + self._test.getBuildArtifact(self._pdb), + os.path.join(pdb_dir, self._pdb), + ) + return self._tmp + + def __exit__(self, *exc_info): + """ + Clean up and delete original exe so next make won't skip link command. + """ + shutil.rmtree(self._tmp) + self._test.runCmd("settings clear plugin.symbol-locator.symstore") + os.remove(self._test.getBuildArtifact(self._exe)) + + +class SymStoreLocalTests(TestBase): + TEST_WITH_PDB_DEBUG_INFO = True + + def build_inferior(self): + if self.getDebugInfo() != "pdb": + self.skipTest("Non-PDB debug info variants not yet supported") + self.build() + exe_file = "a.out" + sym_file = "a.pdb" + self.assertTrue(os.path.isfile(self.getBuildArtifact(exe_file))) + self.assertTrue(os.path.isfile(self.getBuildArtifact(sym_file))) + return exe_file, sym_file + + def try_breakpoint(self, exe, should_have_loc, ext_lookup=True): + enable = "true" if ext_lookup else "false" + self.runCmd(f"settings set symbols.enable-external-lookup {enable}") + target = self.dbg.CreateTarget(self.getBuildArtifact(exe)) + 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 if should_have_loc else 0) + self.dbg.DeleteTarget(target) + + def test_no_symstore_url(self): + """ + Check that breakpoint doesn't resolve without SymStore. + """ + exe, sym = self.build_inferior() + with MockedSymStore(self, exe, sym): + self.try_breakpoint(exe, should_have_loc=False) + + def test_external_lookup_off(self): + """ + Check that breakpoint doesn't resolve with external lookup disabled. + """ + exe, sym = self.build_inferior() + with MockedSymStore(self, exe, sym) as symstore_dir: + self.runCmd( + f"settings set plugin.symbol-locator.symstore.urls {symstore_dir}" + ) + self.try_breakpoint(exe, ext_lookup=False, should_have_loc=False) + + def test_basic(self): + """ + Check that breakpoint resolves with local SymStore. + """ + exe, sym = self.build_inferior() + with MockedSymStore(self, exe, sym) as symstore_dir: + self.runCmd( + f"settings set plugin.symbol-locator.symstore.urls {symstore_dir}" + ) + self.try_breakpoint(exe, should_have_loc=True) diff --git a/lldb/test/API/symstore/main.c b/lldb/test/API/symstore/main.c new file mode 100644 index 0000000000000..a95762e80ea44 --- /dev/null +++ b/lldb/test/API/symstore/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 f9d329ce25fca6f60967dce8e1aa8540672b2b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Tue, 10 Mar 2026 14:08:26 +0100 Subject: [PATCH 2/8] Create mock symstore in build directory and not in mkdtemp --- lldb/test/API/symstore/TestSymStoreLocal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/symstore/TestSymStoreLocal.py b/lldb/test/API/symstore/TestSymStoreLocal.py index 154af876fea3f..cedc76ac4354c 100644 --- a/lldb/test/API/symstore/TestSymStoreLocal.py +++ b/lldb/test/API/symstore/TestSymStoreLocal.py @@ -49,7 +49,7 @@ def __enter__(self): if self._test.getDebugInfo() == "pdb": key = self.get_key_pdb(self._exe) self._test.assertIsNotNone(key) - self._tmp = tempfile.mkdtemp() + self._tmp = self._test.getBuildArtifact("tmp") pdb_dir = os.path.join(self._tmp, self._pdb, key) os.makedirs(pdb_dir) shutil.move( @@ -63,8 +63,8 @@ def __exit__(self, *exc_info): Clean up and delete original exe so next make won't skip link command. """ shutil.rmtree(self._tmp) - self._test.runCmd("settings clear plugin.symbol-locator.symstore") os.remove(self._test.getBuildArtifact(self._exe)) + self._test.runCmd("settings clear plugin.symbol-locator.symstore") class SymStoreLocalTests(TestBase): @@ -109,7 +109,7 @@ def test_external_lookup_off(self): ) self.try_breakpoint(exe, ext_lookup=False, should_have_loc=False) - def test_basic(self): + def test_local_dir(self): """ Check that breakpoint resolves with local SymStore. """ From a0f995fbea11999b4ce8a603b958243e9a06d833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Wed, 11 Mar 2026 14:35:37 +0100 Subject: [PATCH 3/8] Stop checking log output in NativePDB/find-pdb-next-to-exe.test --- .../Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test index c35c82ad84d2f..8e71225a5470e 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test +++ b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test @@ -16,14 +16,12 @@ # Regular setup - PDB is at the original path # RUN: %lldb -S %t/init.input -s %t/check.input %t/build/a.exe | FileCheck --check-prefix=BOTH-ORIG %s # BOTH-ORIG: (lldb) target create -# BOTH-ORIG-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}build{{[/\\]}}a.exe # BOTH-ORIG: (A) a = (x = 47) # Move the executable to a different directory but keep the PDB. # RUN: mv %t/build/a.exe %t/dir1 # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=PDB-ORIG %s # PDB-ORIG: (lldb) target create -# PDB-ORIG-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # PDB-ORIG: (A) a = (x = 47) # Copy the PDB to the same directory and all search dirs. LLDB should prefer the original PDB. @@ -36,21 +34,18 @@ # RUN: rm %t/build/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=NEXT-TO-EXE %s # NEXT-TO-EXE: (lldb) target create -# NEXT-TO-EXE-NEXT: Loading {{.*[/\\]}}dir1{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # NEXT-TO-EXE: (A) a = (x = 47) # Remove the PDB next to the exe. LLDB should now use the one in dir2 (first in list). # RUN: rm %t/dir1/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=DIR2 %s # DIR2: (lldb) target create -# DIR2-NEXT: Loading {{.*[/\\]}}dir2{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # DIR2: (A) a = (x = 47) # Remove the PDB in dir2. LLDB should now use the one in dir3 (second in list). # RUN: rm %t/dir2/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=DIR3 %s # DIR3: (lldb) target create -# DIR3-NEXT: Loading {{.*[/\\]}}dir3{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # DIR3: (A) a = (x = 47) # Remove the last PDB in dir3. Now, there's no matching PDB anymore. From 841e342ddc5e07dd8db2e9879305d32e37fb3a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Wed, 11 Mar 2026 15:12:15 +0100 Subject: [PATCH 4/8] Access object file through module once more --- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index e35195fec2efc..26b89eaefd37a 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -239,7 +239,8 @@ uint32_t SymbolFilePDB::CalculateAbilities() { if (!m_session_up) { // Lazily load and match the PDB file, but only do this once. - std::string exePath = m_objfile_sp->GetFileSpec().GetPath(); + std::string exePath = + m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath(); auto error = loadDataForEXE(PDB_ReaderType::DIA, llvm::StringRef(exePath), m_session_up); if (error) { From 4a2facdb024dd8ed18e3045e647e84d419d4c4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Thu, 12 Mar 2026 15:06:12 +0100 Subject: [PATCH 5/8] Move Loading log from loadMatchingPDBFile() to CalculateAbilities() --- .../Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index bed15839be1cd..b094e7afc3dac 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -169,8 +169,6 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { if (expected_info->getGuid() != guid) return nullptr; - LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb->getFilePath(), - exe_path); return pdb; } @@ -398,6 +396,9 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { if (!pdb_file) return 0; + LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb_file->getFilePath(), + m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath()); + auto expected_index = PdbIndex::create(pdb_file); if (!expected_index) { llvm::consumeError(expected_index.takeError()); From e9f2e08c4f9b46681bbd7c60df6e1b4d47e81450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Thu, 12 Mar 2026 15:06:33 +0100 Subject: [PATCH 6/8] Revert "Stop checking log output in NativePDB/find-pdb-next-to-exe.test" This reverts commit a0f995fbea11999b4ce8a603b958243e9a06d833. --- .../Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test index 8e71225a5470e..c35c82ad84d2f 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test +++ b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test @@ -16,12 +16,14 @@ # Regular setup - PDB is at the original path # RUN: %lldb -S %t/init.input -s %t/check.input %t/build/a.exe | FileCheck --check-prefix=BOTH-ORIG %s # BOTH-ORIG: (lldb) target create +# BOTH-ORIG-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}build{{[/\\]}}a.exe # BOTH-ORIG: (A) a = (x = 47) # Move the executable to a different directory but keep the PDB. # RUN: mv %t/build/a.exe %t/dir1 # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=PDB-ORIG %s # PDB-ORIG: (lldb) target create +# PDB-ORIG-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # PDB-ORIG: (A) a = (x = 47) # Copy the PDB to the same directory and all search dirs. LLDB should prefer the original PDB. @@ -34,18 +36,21 @@ # RUN: rm %t/build/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=NEXT-TO-EXE %s # NEXT-TO-EXE: (lldb) target create +# NEXT-TO-EXE-NEXT: Loading {{.*[/\\]}}dir1{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # NEXT-TO-EXE: (A) a = (x = 47) # Remove the PDB next to the exe. LLDB should now use the one in dir2 (first in list). # RUN: rm %t/dir1/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=DIR2 %s # DIR2: (lldb) target create +# DIR2-NEXT: Loading {{.*[/\\]}}dir2{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # DIR2: (A) a = (x = 47) # Remove the PDB in dir2. LLDB should now use the one in dir3 (second in list). # RUN: rm %t/dir2/a.pdb # RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe | FileCheck --check-prefix=DIR3 %s # DIR3: (lldb) target create +# DIR3-NEXT: Loading {{.*[/\\]}}dir3{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe # DIR3: (A) a = (x = 47) # Remove the last PDB in dir3. Now, there's no matching PDB anymore. From 6c09e2d10223b847ade3e8c287889ce35941053c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Thu, 12 Mar 2026 15:14:12 +0100 Subject: [PATCH 7/8] clang-format --- .../Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index b094e7afc3dac..d083768c3cdd0 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -396,8 +396,10 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { if (!pdb_file) return 0; - LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb_file->getFilePath(), - m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath()); + LLDB_LOG( + GetLog(LLDBLog::Symbols), "Loading {0} for {1}", + pdb_file->getFilePath(), + m_objfile_sp->GetModule()->GetObjectFile()->GetFileSpec().GetPath()); auto expected_index = PdbIndex::create(pdb_file); if (!expected_index) { From cde6d13b1552070c6949bd4d172d3013dccc0e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <[email protected]> Date: Mon, 16 Mar 2026 08:42:05 +0100 Subject: [PATCH 8/8] Set module path as implicit first search path for PDB --- .../SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp index 1797e5b7677ee..87436da443d91 100644 --- a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp +++ b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp @@ -69,11 +69,20 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp, lldb::eSectionTypeDWARFDebugInfo, true)) return nullptr; + // Otherwise, we try to locate it. + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); + // 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, if this is CodeView, use the PDB path and set the module + // directory as the first fallback lookup location. + if (!fspec) { + if (auto pdb_spec = obj_file->GetPDBPath()) { + fspec = *pdb_spec; + if (ConstString dir = obj_file->GetFileSpec().GetDirectory()) + search_paths.Insert(0, FileSpec(dir)); + } + } // Otherwise, try gnu_debuglink, if one exists. if (!fspec) fspec = obj_file->GetDebugLink().value_or(FileSpec()); @@ -87,7 +96,6 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp, FileSystem::Instance().Resolve(module_spec.GetFileSpec()); module_spec.GetSymbolFileSpec() = fspec; module_spec.GetUUID() = uuid; - FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); FileSpec dsym_fspec = PluginManager::LocateExecutableSymbolFile( module_spec, search_paths, module_sp->GetSymbolLocatorStatistics()); if (!dsym_fspec) _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
