https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/178747
>From 2b8d17a3538bbd56dc5295661b49b66f58596679 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Fri, 30 Jan 2026 01:02:50 +0500 Subject: [PATCH 1/3] [lldb] Add evaluation modes to DIL DIL will only attempt evaluating expressions that contain tokens allowed by a selected mode: - Simple: identifiers, operators: '.' - Legacy: identifiers, integers, operators: '.', '->', '*', '&', '[]' - Full: everything supported by DIL --- lldb/include/lldb/API/SBFrame.h | 10 +++++--- lldb/include/lldb/Target/BorrowedStackFrame.h | 3 ++- lldb/include/lldb/Target/StackFrame.h | 10 ++++++-- lldb/include/lldb/ValueObject/DILLexer.h | 4 +++- lldb/include/lldb/lldb-enumerations.h | 13 ++++++++++ lldb/source/API/SBFrame.cpp | 10 ++++---- .../Commands/CommandObjectDWIMPrint.cpp | 4 ++-- lldb/source/Target/BorrowedStackFrame.cpp | 4 ++-- lldb/source/Target/StackFrame.cpp | 9 +++---- lldb/source/ValueObject/DILLexer.cpp | 24 +++++++++++++++++-- .../AddressOf/TestFrameVarDILAddressOf.py | 9 ++++++- .../TestFrameVarDILArraySubscript.py | 9 ++++++- .../LocalVars/TestFrameVarDILLocalVars.py | 9 ++++++- .../MemberOf/TestFrameVarDILMemberOf.py | 22 +++++++++++++---- .../TestFrameVarDILPointerDereference.py | 9 ++++++- .../var-dil/expr/Casts/TestFrameVarDILCast.py | 7 ++++++ .../lldb-dap/evaluate/TestDAP_evaluate.py | 1 + .../Handler/EvaluateRequestHandler.cpp | 2 +- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 4 ++-- 19 files changed, 131 insertions(+), 32 deletions(-) diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h index 5283cdfe53faa..eaf9a4bfece96 100644 --- a/lldb/include/lldb/API/SBFrame.h +++ b/lldb/include/lldb/API/SBFrame.h @@ -182,12 +182,16 @@ class LLDB_API SBFrame { // expression result and is not a constant object like // SBFrame::EvaluateExpression(...) returns, but a child object of the // variable value. - lldb::SBValue GetValueForVariablePath(const char *var_expr_cstr, - DynamicValueType use_dynamic); + lldb::SBValue + GetValueForVariablePath(const char *var_expr_cstr, + DynamicValueType use_dynamic, + lldb::DILMode mode = lldb::eDILModeFull); /// The version that doesn't supply a 'use_dynamic' value will use the /// target's default. - lldb::SBValue GetValueForVariablePath(const char *var_path); + lldb::SBValue + GetValueForVariablePath(const char *var_path, + lldb::DILMode mode = lldb::eDILModeFull); /// Find variables, register sets, registers, or persistent variables using /// the frame as the scope. diff --git a/lldb/include/lldb/Target/BorrowedStackFrame.h b/lldb/include/lldb/Target/BorrowedStackFrame.h index 72e7777961da7..2a34f2816aed2 100644 --- a/lldb/include/lldb/Target/BorrowedStackFrame.h +++ b/lldb/include/lldb/Target/BorrowedStackFrame.h @@ -86,7 +86,8 @@ class BorrowedStackFrame : public StackFrame { lldb::ValueObjectSP GetValueForVariableExpressionPath( llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, - uint32_t options, lldb::VariableSP &var_sp, Status &error) override; + uint32_t options, lldb::VariableSP &var_sp, Status &error, + lldb::DILMode mode = lldb::eDILModeFull) override; bool HasDebugInformation() override; diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index 46922448d6e59..acd76b6fa64c2 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -316,11 +316,16 @@ class StackFrame : public ExecutionContextScope, /// \param[in] error /// Record any errors encountered while evaluating var_expr. /// + /// \param[in] mode + /// Data Inspection Language (DIL) evaluation mode. + /// \see lldb::DILMode + /// /// \return /// A shared pointer to the ValueObject described by var_expr. virtual lldb::ValueObjectSP GetValueForVariableExpressionPath( llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, - uint32_t options, lldb::VariableSP &var_sp, Status &error); + uint32_t options, lldb::VariableSP &var_sp, Status &error, + lldb::DILMode mode = lldb::eDILModeFull); /// Determine whether this StackFrame has debug information available or not. /// @@ -615,7 +620,8 @@ class StackFrame : public ExecutionContextScope, lldb::ValueObjectSP DILGetValueForVariableExpressionPath( llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, - uint32_t options, lldb::VariableSP &var_sp, Status &error); + uint32_t options, lldb::VariableSP &var_sp, Status &error, + lldb::DILMode mode = lldb::eDILModeFull); StackFrame(const StackFrame &) = delete; const StackFrame &operator=(const StackFrame &) = delete; diff --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h index 47b117de7b80d..a927aa236377e 100644 --- a/lldb/include/lldb/ValueObject/DILLexer.h +++ b/lldb/include/lldb/ValueObject/DILLexer.h @@ -9,6 +9,7 @@ #ifndef LLDB_VALUEOBJECT_DILLEXER_H #define LLDB_VALUEOBJECT_DILLEXER_H +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" @@ -74,7 +75,8 @@ class DILLexer { public: /// Lexes all the tokens in expr and calls the private constructor /// with the lexed tokens. - static llvm::Expected<DILLexer> Create(llvm::StringRef expr); + static llvm::Expected<DILLexer> + Create(llvm::StringRef expr, lldb::DILMode mode = lldb::eDILModeFull); /// Return the current token to be handled by the DIL parser. const Token &GetCurrentToken() { return m_lexed_tokens[m_tokens_idx]; } diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 4cbbabbf879ad..67600c8bb4248 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -1420,6 +1420,19 @@ enum NameMatchStyle { eNameMatchStyleRegex = eFunctionNameTypeSelector << 1 }; +/// Data Inspection Language (DIL) evaluation modes. +/// DIL will only attempt evaluating expressions that contain tokens +/// allowed by a selected mode. +enum DILMode { + /// Allowed: identifiers, operators: '.'. + eDILModeSimple, + /// Allowed: identifiers, integers, operators: '.', '->', '*', '&', '[]'. + eDILModeLegacy, + /// Allowed: everything supported by DIL. + /// \see lldb/docs/dil-expr-lang.ebnf + eDILModeFull +}; + } // namespace lldb #endif // LLDB_LLDB_ENUMERATIONS_H diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index 31947a054aaaf..c0f932cc2c43b 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -363,7 +363,8 @@ void SBFrame::Clear() { m_opaque_sp->Clear(); } -lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path) { +lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path, + lldb::DILMode mode) { LLDB_INSTRUMENT_VA(this, var_path); SBValue sb_value; @@ -377,13 +378,14 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path) { if (StackFrame *frame = exe_ctx->GetFramePtr()) { lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue(); - sb_value = GetValueForVariablePath(var_path, use_dynamic); + sb_value = GetValueForVariablePath(var_path, use_dynamic, mode); } return sb_value; } lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path, - DynamicValueType use_dynamic) { + DynamicValueType use_dynamic, + lldb::DILMode mode) { LLDB_INSTRUMENT_VA(this, var_path, use_dynamic); SBValue sb_value; @@ -405,7 +407,7 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path, var_path, eNoDynamicValues, StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, - var_sp, error)); + var_sp, error, mode)); sb_value.SetSP(value_sp, use_dynamic); } return sb_value; diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp index 40f00c90bbbfb..27bd71c21ad3f 100644 --- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -170,8 +170,8 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, Status status; auto valobj_sp = frame->GetValueForVariableExpressionPath( expr, eval_options.GetUseDynamic(), - StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp, - status); + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp, status, + lldb::eDILModeSimple); if (valobj_sp && status.Success() && valobj_sp->GetError().Success()) { if (!suppress_result) { if (auto persisted_valobj = valobj_sp->Persist()) diff --git a/lldb/source/Target/BorrowedStackFrame.cpp b/lldb/source/Target/BorrowedStackFrame.cpp index 5afadf21fde03..5b81a1f05bbfb 100644 --- a/lldb/source/Target/BorrowedStackFrame.cpp +++ b/lldb/source/Target/BorrowedStackFrame.cpp @@ -99,9 +99,9 @@ BorrowedStackFrame::GetInScopeVariableList(bool get_file_globals, ValueObjectSP BorrowedStackFrame::GetValueForVariableExpressionPath( llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options, - VariableSP &var_sp, Status &error) { + VariableSP &var_sp, Status &error, lldb::DILMode mode) { return m_borrowed_frame_sp->GetValueForVariableExpressionPath( - var_expr, use_dynamic, options, var_sp, error); + var_expr, use_dynamic, options, var_sp, error, mode); } bool BorrowedStackFrame::HasDebugInformation() { diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 340607e14abed..9c80e8c0b8ccf 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -524,13 +524,13 @@ StackFrame::GetInScopeVariableList(bool get_file_globals, ValueObjectSP StackFrame::GetValueForVariableExpressionPath( llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options, - VariableSP &var_sp, Status &error) { + VariableSP &var_sp, Status &error, lldb::DILMode mode) { ExecutionContext exe_ctx; CalculateExecutionContext(exe_ctx); bool use_DIL = exe_ctx.GetTargetRef().GetUseDIL(&exe_ctx); if (use_DIL) return DILGetValueForVariableExpressionPath(var_expr, use_dynamic, options, - var_sp, error); + var_sp, error, mode); return LegacyGetValueForVariableExpressionPath(var_expr, use_dynamic, options, var_sp, error); @@ -538,7 +538,8 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath( llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, - uint32_t options, lldb::VariableSP &var_sp, Status &error) { + uint32_t options, lldb::VariableSP &var_sp, Status &error, + lldb::DILMode mode) { const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0; @@ -548,7 +549,7 @@ ValueObjectSP StackFrame::DILGetValueForVariableExpressionPath( (options & eExpressionPathOptionsNoSyntheticChildren) != 0; // Lex the expression. - auto lex_or_err = dil::DILLexer::Create(var_expr); + auto lex_or_err = dil::DILLexer::Create(var_expr, mode); if (!lex_or_err) { error = Status::FromError(lex_or_err.takeError()); return ValueObjectConstResult::Create(nullptr, std::move(error)); diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index 72c97f7bf272b..dc5508cbf706b 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -111,12 +111,32 @@ static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder, return std::nullopt; } -llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr) { +llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr, + lldb::DILMode mode) { std::vector<Token> tokens; llvm::StringRef remainder = expr; do { if (llvm::Expected<Token> t = Lex(expr, remainder)) { - tokens.push_back(std::move(*t)); + Token token = *t; + if (mode == lldb::eDILModeSimple && + !token.IsOneOf({Token::identifier, Token::period, Token::eof})) { + std::string errMsg = + llvm::formatv("token '{0}' is not allowed in DIL simple mode", + Token::GetTokenName(token.GetKind())); + return llvm::make_error<DILDiagnosticError>(expr, errMsg, + token.GetLocation()); + } else if (mode == lldb::eDILModeLegacy && + !token.IsOneOf({Token::identifier, Token::integer_constant, + Token::period, Token::arrow, Token::star, + Token::amp, Token::l_square, Token::r_square, + Token::eof})) { + std::string errMsg = + llvm::formatv("token '{0}' is not allowed in DIL legacy mode", + Token::GetTokenName(token.GetKind())); + return llvm::make_error<DILDiagnosticError>(expr, errMsg, + token.GetLocation()); + } + tokens.push_back(std::move(token)); } else { return t.takeError(); } diff --git a/lldb/test/API/commands/frame/var-dil/basics/AddressOf/TestFrameVarDILAddressOf.py b/lldb/test/API/commands/frame/var-dil/basics/AddressOf/TestFrameVarDILAddressOf.py index 8eab75949047d..bfe29370b4704 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/AddressOf/TestFrameVarDILAddressOf.py +++ b/lldb/test/API/commands/frame/var-dil/basics/AddressOf/TestFrameVarDILAddressOf.py @@ -21,7 +21,7 @@ def expect_var_path(self, expr, compare_to_framevar=False, value=None, type=None def test_frame_var(self): self.build() - lldbutil.run_to_source_breakpoint( + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") ) @@ -36,3 +36,10 @@ def test_frame_var(self): self.expect_var_path("&globalVar", True, type="int *") self.expect_var_path("&s_str", True, type="const char **") self.expect_var_path("&argc", True, type="int *") + + # Check that '&' is not allowed in simple mode, but allowed in legacy mode + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("&x", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("&x", lldb.eDILModeLegacy) + self.assertFailure(simple.GetError()) + self.assertSuccess(legacy.GetError()) diff --git a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py index b22a445e603cd..6f3bbfb970aa4 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py +++ b/lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py @@ -13,7 +13,7 @@ class TestFrameVarDILArraySubscript(TestBase): def test_subscript(self): self.build() - lldbutil.run_to_source_breakpoint( + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") ) @@ -87,6 +87,13 @@ def test_subscript(self): substrs=["subscript of pointer to incomplete type 'void'"], ) + # Check that subscription is not allowed in simple mode, but allowed in legacy mode + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("int_arr[0]", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("int_arr[0]", lldb.eDILModeLegacy) + self.assertFailure(simple.GetError()) + self.assertSuccess(legacy.GetError()) + def test_subscript_synthetic(self): self.build() lldbutil.run_to_source_breakpoint( diff --git a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py index b082d977a3a99..79d8d7abd4671 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py +++ b/lldb/test/API/commands/frame/var-dil/basics/LocalVars/TestFrameVarDILLocalVars.py @@ -16,7 +16,7 @@ class TestFrameVarDILLocalVars(TestBase): def test_frame_var(self): self.build() - lldbutil.run_to_source_breakpoint( + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") ) @@ -25,3 +25,10 @@ def test_frame_var(self): self.expect_var_path("b", value="2") self.expect_var_path("c", value="'\\xfd'") self.expect_var_path("s", value="4") + + # Check that identifiers are allowed in both simple and legacy modes + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("a", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("a", lldb.eDILModeLegacy) + self.assertSuccess(simple.GetError()) + self.assertSuccess(legacy.GetError()) diff --git a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py index ca6754a556d89..d37ce0bbc4201 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py +++ b/lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py @@ -11,6 +11,7 @@ import shutil import time + class TestFrameVarDILMemberOf(TestBase): # If your test case doesn't stress debug info, then # set this to true. That way it won't be run once for @@ -19,11 +20,11 @@ class TestFrameVarDILMemberOf(TestBase): def test_frame_var(self): self.build() - lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here", - lldb.SBFileSpec("main.cpp")) + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") + ) - self.expect("settings set target.experimental.use-DIL true", - substrs=[""]) + self.expect("settings set target.experimental.use-DIL true", substrs=[""]) self.expect_var_path("s.x", value="1") self.expect_var_path("s.r", type="int &") self.expect_var_path("sr.x", value="1") @@ -48,3 +49,16 @@ def test_frame_var(self): # Test for record typedefs. self.expect_var_path("sa.x", value="3") self.expect_var_path("sa.y", value="'\\x04'") + + # Check that '.' is allowed in both simple and legacy modes + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("s.x", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("s.x", lldb.eDILModeLegacy) + self.assertSuccess(simple.GetError()) + self.assertSuccess(legacy.GetError()) + + # Check that '->' is not allowed in simple mode, but allowed in legacy mode + simple = frame.GetValueForVariablePath("sp->x", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("sp->x", lldb.eDILModeLegacy) + self.assertFailure(simple.GetError()) + self.assertSuccess(legacy.GetError()) diff --git a/lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py b/lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py index ffb447441e982..e18e18e146a46 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py +++ b/lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py @@ -17,7 +17,7 @@ class TestFrameVarDILPointerDereference(TestBase): def test_frame_var(self): self.build() - lldbutil.run_to_source_breakpoint( + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") ) @@ -46,3 +46,10 @@ def test_frame_var(self): pp_int0_2stars_got.GetValueAsAddress(), pp_int0_2stars_exp.GetValueAsAddress(), ) + + # Check that * is not allowed in simple mode, but allowed in legacy mode + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("*p_int0", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("*p_int0", lldb.eDILModeLegacy) + self.assertFailure(simple.GetError()) + self.assertSuccess(legacy.GetError()) diff --git a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py index b1f91e55353f3..b84ee9428f669 100644 --- a/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py +++ b/lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py @@ -233,3 +233,10 @@ def test_type_cast(self): self.expect_var_path("((int*)arr_2d)[1]", type="int", value="2") self.expect_var_path("((int*)arr_2d)[2]", type="int", value="3") self.expect_var_path("((int*)arr_2d[1])[1]", type="int", value="5") + + # Check that casts are not allowed in both simple and legacy modes + frame = thread.GetFrameAtIndex(0) + simple = frame.GetValueForVariablePath("(char)a", lldb.eDILModeSimple) + legacy = frame.GetValueForVariablePath("(char)a", lldb.eDILModeLegacy) + self.assertFailure(simple.GetError()) + self.assertFailure(legacy.GetError()) diff --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py index bc08462cfcba9..cc43c42feca7d 100644 --- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py +++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py @@ -241,6 +241,7 @@ def run_test_evaluate_expressions( self.assertEvaluateFailure("a_function(1)") self.assertEvaluateFailure("var2 + struct1.foo") self.assertEvaluateFailure("foo_func") + self.assertEvaluateFailure("(float) var2") self.assertEvaluate("foo_var", "44") # Expressions at breakpoint 2, which is an anonymous block diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index ec26bb66e8aec..9d67714d6d34c 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -72,7 +72,7 @@ EvaluateRequestHandler::Run(const EvaluateArguments &arguments) const { // "frame variable" is more reliable than the expression parser in // many cases and it is faster. lldb::SBValue value = frame.GetValueForVariablePath( - expression.data(), lldb::eDynamicDontRunTarget); + expression.data(), lldb::eDynamicDontRunTarget, lldb::eDILModeLegacy); // Freeze dry the value in case users expand it later in the debug console if (value.GetError().Success() && arguments.context == eEvaluateContextRepl) diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 843a5eb09c7ae..1a9fa7d1b3c02 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -398,8 +398,8 @@ bool SourceBreakpoint::BreakpointHitCallback( // evaluation const std::string &expr_str = messagePart.text; const char *expr = expr_str.c_str(); - lldb::SBValue value = - frame.GetValueForVariablePath(expr, lldb::eDynamicDontRunTarget); + lldb::SBValue value = frame.GetValueForVariablePath( + expr, lldb::eDynamicDontRunTarget, lldb::eDILModeLegacy); if (value.GetError().Fail()) value = frame.EvaluateExpression(expr); output += VariableDescription( >From b239ca54f68972981297ce68d9f8638a01138aeb Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Thu, 5 Feb 2026 20:42:37 +0500 Subject: [PATCH 2/3] Move token checking to a separate function --- lldb/source/ValueObject/DILLexer.cpp | 43 ++++++++++++++++------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index dc5508cbf706b..7936e71c9210a 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -111,6 +111,29 @@ static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder, return std::nullopt; } +static llvm::Error IsNotAllowedByMode(llvm::StringRef expr, Token token, + lldb::DILMode mode) { + if (mode == lldb::eDILModeSimple && + !token.IsOneOf({Token::identifier, Token::period, Token::eof})) { + std::string errMsg = + llvm::formatv("token '{0}' is not allowed in DIL simple mode", + Token::GetTokenName(token.GetKind())); + return llvm::make_error<DILDiagnosticError>(expr, errMsg, + token.GetLocation()); + } else if (mode == lldb::eDILModeLegacy && + !token.IsOneOf({Token::identifier, Token::integer_constant, + Token::period, Token::arrow, Token::star, + Token::amp, Token::l_square, Token::r_square, + Token::eof})) { + std::string errMsg = + llvm::formatv("token '{0}' is not allowed in DIL legacy mode", + Token::GetTokenName(token.GetKind())); + return llvm::make_error<DILDiagnosticError>(expr, errMsg, + token.GetLocation()); + } + return llvm::Error::success(); +} + llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr, lldb::DILMode mode) { std::vector<Token> tokens; @@ -118,24 +141,8 @@ llvm::Expected<DILLexer> DILLexer::Create(llvm::StringRef expr, do { if (llvm::Expected<Token> t = Lex(expr, remainder)) { Token token = *t; - if (mode == lldb::eDILModeSimple && - !token.IsOneOf({Token::identifier, Token::period, Token::eof})) { - std::string errMsg = - llvm::formatv("token '{0}' is not allowed in DIL simple mode", - Token::GetTokenName(token.GetKind())); - return llvm::make_error<DILDiagnosticError>(expr, errMsg, - token.GetLocation()); - } else if (mode == lldb::eDILModeLegacy && - !token.IsOneOf({Token::identifier, Token::integer_constant, - Token::period, Token::arrow, Token::star, - Token::amp, Token::l_square, Token::r_square, - Token::eof})) { - std::string errMsg = - llvm::formatv("token '{0}' is not allowed in DIL legacy mode", - Token::GetTokenName(token.GetKind())); - return llvm::make_error<DILDiagnosticError>(expr, errMsg, - token.GetLocation()); - } + if (llvm::Error error = IsNotAllowedByMode(expr, token, mode)) + return error; tokens.push_back(std::move(token)); } else { return t.takeError(); >From e724c71fd385403ecc2dc3636072e52ad9934126 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Tue, 10 Feb 2026 15:42:27 +0500 Subject: [PATCH 3/3] Check modes in a switch statement --- lldb/source/ValueObject/DILLexer.cpp | 36 +++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index 7936e71c9210a..c1ad354502438 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -113,23 +113,25 @@ static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder, static llvm::Error IsNotAllowedByMode(llvm::StringRef expr, Token token, lldb::DILMode mode) { - if (mode == lldb::eDILModeSimple && - !token.IsOneOf({Token::identifier, Token::period, Token::eof})) { - std::string errMsg = - llvm::formatv("token '{0}' is not allowed in DIL simple mode", - Token::GetTokenName(token.GetKind())); - return llvm::make_error<DILDiagnosticError>(expr, errMsg, - token.GetLocation()); - } else if (mode == lldb::eDILModeLegacy && - !token.IsOneOf({Token::identifier, Token::integer_constant, - Token::period, Token::arrow, Token::star, - Token::amp, Token::l_square, Token::r_square, - Token::eof})) { - std::string errMsg = - llvm::formatv("token '{0}' is not allowed in DIL legacy mode", - Token::GetTokenName(token.GetKind())); - return llvm::make_error<DILDiagnosticError>(expr, errMsg, - token.GetLocation()); + switch (mode) { + case lldb::eDILModeSimple: + if (!token.IsOneOf({Token::identifier, Token::period, Token::eof})) { + return llvm::make_error<DILDiagnosticError>( + expr, llvm::formatv("{0} is not allowed in DIL simple mode", token), + token.GetLocation()); + } + break; + case lldb::eDILModeLegacy: + if (!token.IsOneOf({Token::identifier, Token::integer_constant, + Token::period, Token::arrow, Token::star, Token::amp, + Token::l_square, Token::r_square, Token::eof})) { + return llvm::make_error<DILDiagnosticError>( + expr, llvm::formatv("{0} is not allowed in DIL legacy mode", token), + token.GetLocation()); + } + break; + case lldb::eDILModeFull: + break; } return llvm::Error::success(); } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
