https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/177279
>From 3cc2617c66a3a830b6742957205d1bdff0807e11 Mon Sep 17 00:00:00 2001 From: Adrian Prantl <[email protected]> Date: Wed, 21 Jan 2026 16:06:00 -0800 Subject: [PATCH] [LLDB] Add a setting to simulate variables with missing locations Writing testcases for error handling that depends on specific DWARF is very difficult and the resulting tests tend not to be very portable. This patch adds a new setting to inject an error into variable materialization, thus making it possible to write very simple source code based tests for error handling instead. This is primarily motivated by the Swift language plugin, but functionality is generic and should be useful for other languages as well. --- lldb/include/lldb/Core/ModuleList.h | 15 +++++--- lldb/source/Core/CoreProperties.td | 8 +++++ lldb/source/Core/ModuleList.cpp | 34 ++++++++++++++++++- lldb/source/Symbol/Variable.cpp | 13 +++++-- .../diagnostics/TestExprDiagnostics.py | 17 ++++++++++ 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 1c023031b4c1b..56fe496a732b7 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -88,14 +88,18 @@ class ModuleListProperties : public Properties { uint64_t GetLLDBIndexCacheExpirationDays(); FileSpec GetLLDBIndexCachePath() const; bool SetLLDBIndexCachePath(const FileSpec &path); - - bool GetLoadSymbolOnDemand(); - + bool GetLoadSymbolOnDemand() const; lldb::SymbolDownload GetSymbolAutoDownload() const; - PathMappingList GetSymlinkMappings() const; }; +#ifndef NDEBUG +struct ModuleListTestingProperties : public Properties { + ModuleListTestingProperties(); + bool GetInjectVarLocListError() const; +}; +#endif + /// \class ModuleList ModuleList.h "lldb/Core/ModuleList.h" /// A collection class for Module objects. /// @@ -471,6 +475,9 @@ class ModuleList { bool continue_on_error = true); static ModuleListProperties &GetGlobalModuleListProperties(); +#ifndef NDEBUG + static ModuleListTestingProperties &GetGlobalModuleListTestingProperties(); +#endif static bool ModuleIsInCache(const Module *module_ptr); diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 99bb5a3fc6f73..6c4772201a11a 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -48,6 +48,14 @@ let Definition = "modulelist" in { Desc<"Enable on demand symbol loading in LLDB. LLDB will load debug info on demand for each module based on various conditions (e.g. matched breakpoint, resolved stack frame addresses and matched global variables/function symbols in symbol table) to improve performance. Please refer to docs/use/ondemand.rst for details.">; } +let Definition = "modulelist_testing" in { + def InjectVarLocListError + : Property<"inject-variable-location-error", "Boolean">, + Global, + DefaultFalse, + Desc<"Used for testing LLDB only. Hide locations of local variables.">; +} + let Definition = "debugger" in { def AutoConfirm: Property<"auto-confirm", "Boolean">, Global, diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index f73f1541b7428..96391e1eb4657 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -76,6 +76,16 @@ enum { #include "CorePropertiesEnum.inc" }; +#ifndef NDEBUG +#define LLDB_PROPERTIES_modulelist_testing +#include "CoreProperties.inc" + +enum { +#define LLDB_PROPERTIES_modulelist_testing +#include "CorePropertiesEnum.inc" +}; +#endif + } // namespace ModuleListProperties::ModuleListProperties() { @@ -95,9 +105,21 @@ ModuleListProperties::ModuleListProperties() { llvm::sys::path::append(path, "IndexCache"); lldbassert(SetLLDBIndexCachePath(FileSpec(path))); } +} +#ifndef NDEBUG +ModuleListTestingProperties::ModuleListTestingProperties() { + m_collection_sp = std::make_shared<OptionValueProperties>("symbols.testing"); + m_collection_sp->Initialize(g_modulelist_testing_properties); } +bool ModuleListTestingProperties::GetInjectVarLocListError() const { + const uint32_t idx = ePropertyInjectVarLocListError; + return GetPropertyAtIndexAs<bool>( + idx, g_modulelist_testing_properties[idx].default_uint_value != 0); +} +#endif + bool ModuleListProperties::GetEnableExternalLookup() const { const uint32_t idx = ePropertyEnableExternalLookup; return GetPropertyAtIndexAs<bool>( @@ -186,7 +208,7 @@ PathMappingList ModuleListProperties::GetSymlinkMappings() const { return m_symlink_paths; } -bool ModuleListProperties::GetLoadSymbolOnDemand() { +bool ModuleListProperties::GetLoadSymbolOnDemand() const { const uint32_t idx = ePropertyLoadSymbolOnDemand; return GetPropertyAtIndexAs<bool>( idx, g_modulelist_properties[idx].default_uint_value != 0); @@ -999,6 +1021,9 @@ class SharedModuleList { struct SharedModuleListInfo { SharedModuleList module_list; ModuleListProperties module_list_properties; +#ifndef NDEBUG + ModuleListTestingProperties module_list_testing_properties; +#endif }; } static SharedModuleListInfo &GetSharedModuleListInfo() @@ -1023,6 +1048,13 @@ ModuleListProperties &ModuleList::GetGlobalModuleListProperties() { return GetSharedModuleListInfo().module_list_properties; } +#ifndef NDEBUG +ModuleListTestingProperties & +ModuleList::GetGlobalModuleListTestingProperties() { + return GetSharedModuleListInfo().module_list_testing_properties; +} +#endif + bool ModuleList::ModuleIsInCache(const Module *module_ptr) { if (module_ptr) { SharedModuleList &shared_module_list = GetSharedModuleList(); diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp index af32e0e958e51..0a191e375c4a3 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -47,9 +47,16 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, : UserID(uid), m_name(name), m_mangled(ConstString(mangled)), m_symfile_type_sp(symfile_type_sp), m_scope(scope), m_owner_scope(context), m_scope_range(scope_range), - m_declaration(decl_ptr), m_location_list(location_list), m_external(external), - m_artificial(artificial), m_loc_is_const_data(location_is_constant_data), - m_static_member(static_member) {} + m_declaration(decl_ptr), m_location_list(location_list), + m_external(external), m_artificial(artificial), + m_loc_is_const_data(location_is_constant_data), + m_static_member(static_member) { +#ifndef NDEBUG + if (ModuleList::GetGlobalModuleListTestingProperties() + .GetInjectVarLocListError()) + m_location_list.Clear(); +#endif +} Variable::~Variable() = default; diff --git a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py index 759b620105c4e..c88dbf6470c02 100644 --- a/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py +++ b/lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py @@ -272,3 +272,20 @@ def check_error(diags): self.assertEqual(err_ty.GetIntegerValue(), lldb.eErrorTypeExpression) diags = data.GetValueForKey("errors").GetItemAtIndex(0) check_error(diags) + + def test_no_location(self): + """Test the error reporting for missing locations""" + self.build() + + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "// Break here", self.main_source_spec + ) + self.ci.HandleCommand('settings set symbols.testing.inject-variable-location-error true', self.res) + if not self.res.Succeeded(): + # This test needs assertions. + return + frame = thread.GetFrameAtIndex(0) + value = frame.EvaluateExpression('f') + error = value.GetError() + self.assertIn('variable not available', str(error)) + _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
