https://github.com/hawkinsw updated https://github.com/llvm/llvm-project/pull/215706
>From 8bfc4321853e0794450b63e751b776d25453bf92 Mon Sep 17 00:00:00 2001 From: Will Hawkins <[email protected]> Date: Tue, 11 Aug 2026 21:46:30 -0400 Subject: [PATCH] [lldb] Support Persistent Variables as DIL Identifiers When a persistent variable is used in a DIL expression, look it up as if it were any other identifier in the global scope. Signed-off-by: Will Hawkins <[email protected]> --- lldb/include/lldb/ValueObject/DILEval.h | 7 ++ .../Commands/CommandObjectDWIMPrint.cpp | 10 -- lldb/source/ValueObject/DILEval.cpp | 35 +++++++ .../PersistentResultVariableLookup/Makefile | 3 + .../TestFrameVarDILGlobalVariableLookup.py | 96 +++++++++++++++++++ .../PersistentResultVariableLookup/main.cpp | 23 +++++ 6 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py create mode 100644 lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h index 489dc801b20db..3a873063adda1 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -18,6 +18,13 @@ namespace lldb_private::dil { +/// Given the name of a persistent identifier (i.e., one that starts with a $), +/// find the ValueObject for that name (if it exists). +lldb::ValueObjectSP LookupPersistentIdentifier(llvm::StringRef name_ref, + StackFrame &stack_frame, + lldb::TargetSP target_sp, + lldb::LanguageType language); + /// Given the name of an identifier (variable name, member name, type name, /// etc.), find the ValueObject for that name (if it exists), excluding global /// variables, and create and return an IdentifierInfo object containing all diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp index 1b0b4c7881cfc..5b3f5707b3bef 100644 --- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -191,16 +191,6 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, } } - // Second, try `expr` as a persistent variable. - if (expr.starts_with("$")) - if (auto *state = target.GetPersistentExpressionStateForLanguage( - language.AsLanguageType())) - if (auto var_sp = state->GetVariable(expr)) - if (auto valobj_sp = var_sp->GetValueObject()) { - dump_val_object(*valobj_sp); - return; - } - // Third, and lastly, try `expr` as a source expression to evaluate. { auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 0ef4e244410a4..853d085f221cc 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -8,10 +8,12 @@ #include "lldb/ValueObject/DILEval.h" #include "lldb/Core/Module.h" +#include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/ValueObject/DILAST.h" #include "lldb/ValueObject/DILParser.h" @@ -44,6 +46,17 @@ static lldb::ValueObjectSP ArrayToPointerConversion(ValueObject &valobj, /* do_deref */ false); } +static llvm::Expected<lldb::LanguageType> +GetSourceLanguageFromCU(StackFrame &ctx) { + SymbolContext symbol_context = + ctx.GetSymbolContext(lldb::eSymbolContextCompUnit); + if (!symbol_context.comp_unit) + return llvm::createStringErrorV("no compile unit for frame: {}", + ctx.GetFunctionName()); + + return symbol_context.comp_unit->GetLanguage(); +} + static llvm::Expected<lldb::TypeSystemSP> GetTypeSystemFromCU(StackFrame &ctx) { SymbolContext symbol_context = ctx.GetSymbolContext(lldb::eSymbolContextCompUnit); @@ -323,6 +336,20 @@ lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef name_ref, return nullptr; } +lldb::ValueObjectSP LookupPersistentIdentifier(llvm::StringRef name_ref, + StackFrame &stack_frame, + lldb::TargetSP target_sp, + lldb::LanguageType language) { + if (name_ref.starts_with("$")) { + if (auto *state = + target_sp->GetPersistentExpressionStateForLanguage(language)) + if (auto var_sp = state->GetVariable(name_ref)) + if (auto valobj_sp = var_sp->GetValueObject()) + return valobj_sp; + } + return nullptr; +} + lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref, StackFrame &stack_frame, lldb::DynamicValueType use_dynamic) { @@ -459,6 +486,14 @@ Interpreter::Visit(const IdentifierNode &node) { if (!identifier) identifier = LookupEnumValue(node.GetName(), m_stack_frame); + if (!identifier && node.GetName()[0] == '$') { + auto language = GetSourceLanguageFromCU(m_stack_frame); + if (!language) + return language.takeError(); + identifier = LookupPersistentIdentifier(node.GetName(), m_stack_frame, + m_target, language.get()); + } + if (!identifier && node.GetName() == "nullptr") { // If we got a "nullptr" identifier, and there is no defined variable with // this name, resolve it as a null pointer. diff --git a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py new file mode 100644 index 0000000000000..36a44dfc08806 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/TestFrameVarDILGlobalVariableLookup.py @@ -0,0 +1,96 @@ +""" +Make sure 'frame var' using DIL parser/evaluator works for persistent/result variables. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + +import os +import shutil +import time + + +class TestFrameVarDILGlobalVariableLookup(TestBase): + # If your test case doesn't stress debug info, then + # set this to true. That way it won't be run once for + # each debug info format. + NO_DEBUG_INFO_TESTCASE = True + + @skipIf(macos_version=["<", "15.0"], archs=["arm64", "arm64e"]) + @skipIf( + dwarf_version=["<", "5"], + oslist=[lldbplatformutil.getDarwinOSTriples()], + ) + @expectedFailureAll( + compiler="clang", + compiler_version=["<", "19.0"], + oslist=[lldbplatformutil.getDarwinOSTriples()], + ) + def test_frame_var(self): + self.build() + _, process, _, _ = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") + ) + + self.runCmd("settings set target.experimental.use-DIL true") + + # Establish a persistent variable with integer type. + self.expect( + "dwim-print --persistent-result true -- foo + 5", startstr="(int) $0 = " + ) + self.expect_var_path("$0", type="int", value="6") + + # Establish a persistent variable using dwim-print with derived type (using C specification terminology). + self.expect( + "dwim-print --persistent-result true -- hsmt", + startstr="(HasMembersT) $1 = ", + ) + self.expect_var_path( + "$1", + type="HasMembersT", + children=[ + ValueCheck(name="intm", value="1", type="int"), + ValueCheck(name="doublem", value="2", type="double"), + ValueCheck( + name="nestedm", + type="NestedT", + children=[ValueCheck(name="charm", type="char", value="'c'")], + ), + ], + ) + # Check that accessing fields of persistent variables works. + self.expect_var_path("$1.intm", type="int", value="1") + self.expect_var_path("$1.nestedm.charm", type="char", value="'c'") + self.expect_var_path("$1.intm + $0", type="int", value="7") + + # Check that types work correctly when adding an int and a double. + self.expect_var_path("$1.intm + $1.doublem", type="double", value="3") + + # Establish persistent variable using expression. + self.expect( + "expression foo", + startstr="(int) $2 = 1", + ) + self.expect_var_path("$2", type="int", value="1") + + # Establish persistent variables with user-defined names. + self.runCmd( + "expression int *$foop = &foo", + ) + self.runCmd( + "expression HasMembersT *$hsmtp = &hsmt", + ) + + self.expect_var_path("*$foop", type="int", value="1") + self.expect_var_path("(*$hsmtp).doublem", type="double", value="2") + + # Step past statements that update variable values. + lldbutil.continue_to_source_breakpoint( + self, process, "Set a second breakpoint here", lldb.SBFileSpec("main.cpp") + ) + + # Make sure that the value accessed through the pointer in persistent variables are updated. + self.expect_var_path("*$foop", type="int", value="2") + self.expect_var_path("(*$hsmtp).doublem", type="double", value="3") diff --git a/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp new file mode 100644 index 0000000000000..1bdcf11b92480 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/PersistentResultVariableLookup/main.cpp @@ -0,0 +1,23 @@ +typedef struct { + char charm; +} NestedT; + +typedef struct { + int intm; + double doublem; + NestedT nestedm; + +} HasMembersT; + +int main(int argc, char **argv) { + HasMembersT hsmt; + + hsmt.nestedm.charm = 'c'; + hsmt.intm = 1; + hsmt.doublem = 2.0; + + int foo = 1; + foo = 2; // Set a breakpoint here + hsmt.doublem = 3.0; + return 0; // Set a second breakpoint here +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
