https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/222192
>From 858d4947fa11931f15d1fe57686065c4d812da66 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Mon, 7 Sep 2026 21:10:14 +0500 Subject: [PATCH 1/5] [lldb] Use DIL in SBValue::CreateValueFromExpression --- lldb/include/lldb/Target/Target.h | 4 ++ lldb/source/API/SBValue.cpp | 49 ++++++++++++++++-- lldb/source/Target/Target.cpp | 22 ++++++++ lldb/source/Target/TargetProperties.td | 3 ++ .../expr/CreateValueFromExpression/Makefile | 3 ++ .../TestCreateValueFromExpression.py | 51 +++++++++++++++++++ .../expr/CreateValueFromExpression/main.cpp | 7 +++ 7 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py create mode 100644 lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/main.cpp diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 31a59a8501338..6ee72bf0d288b 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -281,6 +281,10 @@ class TargetProperties : public Properties { void SetUseDIL(ExecutionContext *exe_ctx, bool b); + bool GetUseDILForCreatingValues() const; + + void SetUseDILForCreatingValues(bool b); + void SetRequireHardwareBreakpoints(bool b); bool GetRequireHardwareBreakpoints() const; diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 32fbe1ecf15b0..822e18df7d199 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -473,18 +473,57 @@ lldb::SBValue SBValue::CreateValueFromExpression(const char *name, SBExpressionOptions &options) { LLDB_INSTRUMENT_VA(this, name, expression, options); - lldb::SBValue sb_value; + lldb::ValueObjectSP new_value_sp; + StackFrameSP frame_sp(GetFrame().GetFrameSP()); + TargetSP target_sp(GetTarget().GetSP()); + // If enabled, attempt to use DIL to evaluate the expression. + bool DIL_success = false; + if (frame_sp && target_sp) { + bool use_DIL = target_sp->GetUseDILForCreatingValues(); + if (use_DIL) { + Status error; + if (frame_sp) { + uint32_t expr_path_options = + StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; + lldb::VariableSP var_sp; + new_value_sp = frame_sp->GetValueForVariableExpressionPath( + expression, eNoDynamicValues, expr_path_options, var_sp, error); + } + DIL_success = new_value_sp && new_value_sp->GetError().Success(); + } + } + ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); - lldb::ValueObjectSP new_value_sp; - if (value_sp) { + // Fall back to full expression evaluation if DIL did not succeed. + if (!DIL_success && value_sp) { ExecutionContext exe_ctx(value_sp->GetExecutionContextRef()); new_value_sp = value_sp->CreateChildValueObjectFromExpression( name, expression, exe_ctx, options.ref()); - if (new_value_sp) - new_value_sp->SetName(name); } + + if (new_value_sp) + new_value_sp->SetName(name); + lldb::SBValue sb_value; sb_value.SetSP(new_value_sp); + + Log *log = GetLog(LLDBLog::Expressions); + if (new_value_sp && new_value_sp->GetError().Success()) + LLDB_LOGF(log, + "** [SBValue::CreateValueFromExpression] Expression result: " + "(%s) %s = %s (evaluated by: %s) **", + new_value_sp->GetTypeName().GetCString(), + new_value_sp->GetName().GetCString(), + new_value_sp->GetValueAsCString(), + DIL_success ? "DIL" : "UserExpression"); + else + LLDB_LOGF(log, + "** [SBValue::CreateValueFromExpression] Expression evaluation " + "failed: %s **", + new_value_sp ? new_value_sp->GetError().AsCString() + : "unknown error"); + return sb_value; } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 928292799be21..20c94d98eca56 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -5223,6 +5223,28 @@ void TargetProperties::SetUseDIL(ExecutionContext *exe_ctx, bool b) { exp_values->SetPropertyAtIndex(ePropertyUseDIL, true, exe_ctx); } +bool TargetProperties::GetUseDILForCreatingValues() const { + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + return exp_values + ->GetPropertyAtIndexAs<bool>(ePropertyUseDILForCreatingValues) + .value_or(false); + else + return true; +} + +void TargetProperties::SetUseDILForCreatingValues(bool b) { + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + exp_values->SetPropertyAtIndex(ePropertyUseDILForCreatingValues, b); +} + ArchSpec TargetProperties::GetDefaultArchitecture() const { const uint32_t idx = ePropertyDefaultArch; return GetPropertyAtIndexAs<ArchSpec>(idx, {}); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 7b296da45b26e..3d717fe334b44 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -7,6 +7,9 @@ let Definition = "target_experimental", Path = "target.experimental" in { def UseDIL : Property<"use-DIL", "Boolean">, Global, DefaultTrue, Desc<"If true, use the DIL implementation for frame variable evaluation.">; + def UseDILForCreatingValues: Property<"use-DIL-for-creating-values", "Boolean">, + Global, DefaultTrue, + Desc<"If true, use the DIL implementation to create variables from expressions.">; } let Definition = "target", Path = "target" in { diff --git a/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/Makefile b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py new file mode 100644 index 0000000000000..bfc202c96772f --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py @@ -0,0 +1,51 @@ +""" +Test how DIL is used in SBValue::CreateValueFromExpression. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + + +class TestCreateValueFromExpression(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_formatter(self): + self.build() + (_, _, thread, _) = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") + ) + + # Enable logging + log_file = self.getBuildArtifact("log-file.txt") + if os.path.exists(log_file): + os.remove(log_file) + self.runCmd("log enable -f '%s' lldb expr" % (log_file)) + + self.runCmd("settings set target.experimental.use-DIL true") + self.runCmd("settings set target.experimental.use-DIL-for-creating-values true") + + # Check expression results + frame = thread.GetFrameAtIndex(0) + i = frame.FindVariable("i") + v1 = i.CreateValueFromExpression("v1", "i + 1") + self.assertEqual(v1.GetValue(), "1") + v2 = i.CreateValueFromExpression("v2", "static_cast<double>(i) + 2.5") + self.assertEqual(v2.GetValue(), "2.5") + self.runCmd( + "settings set target.experimental.use-DIL-for-creating-values false" + ) + v3 = i.CreateValueFromExpression("v3", "i + 3") + self.assertEqual(v3.GetValue(), "3") + + with open(log_file, "r") as f: + log = f.read() + + # Check that supported expression is evaluated by DIL + self.assertGreater(log.find("v1 = 1 (evaluated by: DIL)"), 0) + # Check that if DIL cannot evaluate the expression, it falls back to + # full expression evaluation + self.assertGreater(log.find("v2 = 2.5 (evaluated by: UserExpression)"), 0) + # Check that creating values using DIL was disabled for the 3rd expression + self.assertGreater(log.find("v3 = 3 (evaluated by: UserExpression)"), 0) diff --git a/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/main.cpp new file mode 100644 index 0000000000000..0435ca02d5605 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/main.cpp @@ -0,0 +1,7 @@ +void stop() {} + +int main() { + int i = 0; + + stop(); // Set a breakpoint here +} >From a84f9142a88933bc8a12b62106f4254cd665b98e Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Wed, 9 Sep 2026 21:00:02 +0500 Subject: [PATCH 2/5] Remove a check, pass the dynamic value option --- lldb/source/API/SBValue.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 822e18df7d199..1d1263060ff69 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -482,14 +482,13 @@ lldb::SBValue SBValue::CreateValueFromExpression(const char *name, bool use_DIL = target_sp->GetUseDILForCreatingValues(); if (use_DIL) { Status error; - if (frame_sp) { - uint32_t expr_path_options = - StackFrame::eExpressionPathOptionCheckPtrVsMember | - StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; - lldb::VariableSP var_sp; - new_value_sp = frame_sp->GetValueForVariableExpressionPath( - expression, eNoDynamicValues, expr_path_options, var_sp, error); - } + uint32_t expr_path_options = + StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; + lldb::VariableSP var_sp; + new_value_sp = frame_sp->GetValueForVariableExpressionPath( + expression, options.GetFetchDynamicValue(), expr_path_options, var_sp, + error); DIL_success = new_value_sp && new_value_sp->GetError().Success(); } } >From 6b6088bcae4524a0c26a81a418048bbaf6c6a435 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Wed, 9 Sep 2026 21:51:07 +0500 Subject: [PATCH 3/5] Add comments and documentation --- lldb/bindings/interface/SBValueDocstrings.i | 9 +++++++++ lldb/include/lldb/API/SBValue.h | 6 ++++++ lldb/source/Target/TargetProperties.td | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lldb/bindings/interface/SBValueDocstrings.i b/lldb/bindings/interface/SBValueDocstrings.i index 627036b6c0c66..08e697e2bf7b2 100644 --- a/lldb/bindings/interface/SBValueDocstrings.i +++ b/lldb/bindings/interface/SBValueDocstrings.i @@ -230,3 +230,12 @@ linked list." or a constant. A success result does not guarantee a write will succeed; other runtime conditions may still prevent a successful write." ) lldb::SBValue::CanSet; + +%feature("docstring", " + Create an SBValue with the given name by evaluating the expression, with + the execution context inherited from the current SBValue. + Data Inspection Language (DIL) attempts to evaluate the expression first + (can be disabled by setting target.experimental.use-DIL-for-creating-values + to false). If DIL is not called or fails, the evaluation falls back to + UserExpression." +) lldb::SBValue::CreateValueFromExpression; diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index bbaa28762328e..fe2b90e305196 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -165,6 +165,12 @@ class LLDB_API SBValue { LLDB_DEPRECATED("Use the expression evaluator to perform type casting") lldb::SBValue Cast(lldb::SBType type); + /// Create an SBValue with the given name by evaluating the expression, with + /// the execution context inherited from the current SBValue. + /// Data Inspection Language (DIL) attempts to evaluate the expression first + /// (can be disabled by target.experimental.use-DIL-for-creating-values) + /// If DIL is not called or fails, the evaluation falls back to + /// UserExpression. lldb::SBValue CreateValueFromExpression(const char *name, const char *expression); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 3d717fe334b44..4ba6791e3183d 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -9,7 +9,7 @@ let Definition = "target_experimental", Path = "target.experimental" in { Desc<"If true, use the DIL implementation for frame variable evaluation.">; def UseDILForCreatingValues: Property<"use-DIL-for-creating-values", "Boolean">, Global, DefaultTrue, - Desc<"If true, use the DIL implementation to create variables from expressions.">; + Desc<"If true, use the DIL implementation in API SBValue::CreateValueFromExpression.">; } let Definition = "target", Path = "target" in { >From 1bf67a332449dba260d9fd6b9f7a124722c3e8f3 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Fri, 11 Sep 2026 21:01:05 +0500 Subject: [PATCH 4/5] Add a DIL option to SBExpressionOptions and use it --- lldb/include/lldb/API/SBExpressionOptions.h | 4 ++++ lldb/include/lldb/Target/Target.h | 8 ++++++++ lldb/source/API/SBExpressionOptions.cpp | 12 ++++++++++++ lldb/source/API/SBValue.cpp | 6 ++++-- .../TestCreateValueFromExpression.py | 16 +++++++++++++--- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h index 8dcd6ea8e511a..96adc084d86f1 100644 --- a/lldb/include/lldb/API/SBExpressionOptions.h +++ b/lldb/include/lldb/API/SBExpressionOptions.h @@ -115,6 +115,10 @@ class LLDB_API SBExpressionOptions { SBError SetBooleanLanguageOption(const char *option_name, bool value); + bool GetTryDILFirst(); + + void SetTryDILFirst(bool b = true); + protected: lldb_private::EvaluateExpressionOptions *get() const; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 6ee72bf0d288b..0b4290ad4a33d 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -534,6 +534,10 @@ class EvaluateExpressionOptions { bool GetCppIgnoreContextQualifiers() const; + void SetTryDILFirst(bool b) { m_try_DIL_first = b; } + + bool GetTryDILFirst() const { return m_try_DIL_first; } + private: const StructuredData::Dictionary &GetLanguageOptions() const; @@ -560,6 +564,10 @@ class EvaluateExpressionOptions { /// True if the executed code should be treated as utility code that is only /// used by LLDB internally. bool m_running_utility_expression = false; + /// If enabled, Data Inspection Language (DIL) should attempt to evaluate the + /// expression first. If DIL is not called or fails, the evaluation falls + /// back to UserExpression. + bool m_try_DIL_first = false; lldb::DynamicValueType m_use_dynamic = lldb::eNoDynamicValues; Timeout<std::micro> m_timeout = default_timeout; diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp index 7786daa98d1cb..36afca66debfe 100644 --- a/lldb/source/API/SBExpressionOptions.cpp +++ b/lldb/source/API/SBExpressionOptions.cpp @@ -301,6 +301,18 @@ SBError SBExpressionOptions::SetBooleanLanguageOption(const char *option_name, return error; } +bool SBExpressionOptions::GetTryDILFirst() { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up->GetTryDILFirst(); +} + +void SBExpressionOptions::SetTryDILFirst(bool b) { + LLDB_INSTRUMENT_VA(this, b); + + return m_opaque_up->SetTryDILFirst(b); +} + EvaluateExpressionOptions *SBExpressionOptions::get() const { return m_opaque_up.get(); } diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 1d1263060ff69..449cafb85ef64 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -465,6 +465,9 @@ lldb::SBValue SBValue::CreateValueFromExpression(const char *name, SBExpressionOptions options; options.ref().SetKeepInMemory(true); + TargetSP target_sp(GetTarget().GetSP()); + if (target_sp) + options.SetTryDILFirst(target_sp->GetUseDILForCreatingValues()); return CreateValueFromExpression(name, expression, options); } @@ -479,8 +482,7 @@ lldb::SBValue SBValue::CreateValueFromExpression(const char *name, // If enabled, attempt to use DIL to evaluate the expression. bool DIL_success = false; if (frame_sp && target_sp) { - bool use_DIL = target_sp->GetUseDILForCreatingValues(); - if (use_DIL) { + if (options.GetTryDILFirst()) { Status error; uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | diff --git a/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py index bfc202c96772f..f105adc87ac14 100644 --- a/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py +++ b/lldb/test/API/commands/frame/var-dil/expr/CreateValueFromExpression/TestCreateValueFromExpression.py @@ -33,11 +33,17 @@ def test_formatter(self): self.assertEqual(v1.GetValue(), "1") v2 = i.CreateValueFromExpression("v2", "static_cast<double>(i) + 2.5") self.assertEqual(v2.GetValue(), "2.5") + expr_options = lldb.SBExpressionOptions() + v3 = i.CreateValueFromExpression("v3", "i + 3", expr_options) + self.assertEqual(v3.GetValue(), "3") self.runCmd( "settings set target.experimental.use-DIL-for-creating-values false" ) - v3 = i.CreateValueFromExpression("v3", "i + 3") - self.assertEqual(v3.GetValue(), "3") + v4 = i.CreateValueFromExpression("v4", "i + 4") + self.assertEqual(v4.GetValue(), "4") + expr_options.SetTryDILFirst(True) + v5 = i.CreateValueFromExpression("v5", "i + 5", expr_options) + self.assertEqual(v5.GetValue(), "5") with open(log_file, "r") as f: log = f.read() @@ -47,5 +53,9 @@ def test_formatter(self): # Check that if DIL cannot evaluate the expression, it falls back to # full expression evaluation self.assertGreater(log.find("v2 = 2.5 (evaluated by: UserExpression)"), 0) - # Check that creating values using DIL was disabled for the 3rd expression + # Check that trying DIL can be disabled through expression options parameter self.assertGreater(log.find("v3 = 3 (evaluated by: UserExpression)"), 0) + # Check that using DIL was disabled after disabling the lldb setting + self.assertGreater(log.find("v4 = 4 (evaluated by: UserExpression)"), 0) + # Check that trying DIL can be enabled through expression options parameter + self.assertGreater(log.find("v5 = 5 (evaluated by: DIL)"), 0) >From 641cbed0644f828ab64a8a05e50b3b51228887ec Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Sat, 12 Sep 2026 18:07:59 +0500 Subject: [PATCH 5/5] Remove unused return --- lldb/source/API/SBExpressionOptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp index 36afca66debfe..9fbd1c70f9d57 100644 --- a/lldb/source/API/SBExpressionOptions.cpp +++ b/lldb/source/API/SBExpressionOptions.cpp @@ -310,7 +310,7 @@ bool SBExpressionOptions::GetTryDILFirst() { void SBExpressionOptions::SetTryDILFirst(bool b) { LLDB_INSTRUMENT_VA(this, b); - return m_opaque_up->SetTryDILFirst(b); + m_opaque_up->SetTryDILFirst(b); } EvaluateExpressionOptions *SBExpressionOptions::get() const { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
