Author: Ebuka Ezike
Date: 2026-08-28T20:16:15+01:00
New Revision: 4e1a982f130bcd329a062e6c458c3d8818b6ddf3

URL: 
https://github.com/llvm/llvm-project/commit/4e1a982f130bcd329a062e6c458c3d8818b6ddf3
DIFF: 
https://github.com/llvm/llvm-project/commit/4e1a982f130bcd329a062e6c458c3d8818b6ddf3.diff

LOG: [lldb] Fix SBAPI breakage in SBFrame::GetValueForVariablePath (#218565)

SBFrame::GetValueForVariablePath added new parameters in commit
80fffd527c20ac8970fbffc37c674caa17faa815.
This caused an ABI break because
the ABI is based on the function's mangled name, which changes when
parameters are added. Existing users depend on the original symbol being
present in the library.
changing the ABI from:
```cpp
// _ZN4lldb7SBFrame23GetValueForVariablePathEPKcNS_16DynamicValueTypeE
lldb::SBFrame::GetValueForVariablePath(char const*, lldb::DynamicValueType)
```
to
```cpp
// 
_ZN4lldb7SBFrame23GetValueForVariablePathEPKcNS_16DynamicValueTypeENS_7DILModeE`
lldb::SBFrame::GetValueForVariablePath(char const*, lldb::DynamicValueType, 
lldb::DILMode)
```


Normally, this can be fixed by manually overloading the function from:
```cpp
GetValueForVariablePath(const char *, DynamicValueType, lldb::DILMode = 
lldb::eDILModeFull);
```
to
```cpp
GetValueForVariablePath(const char *, DynamicValueType);
GetValueForVariablePath(const char *, DynamicValueType, lldb::DILMode mode);
```
with the two-argument overload setting the mode in the implementation.

However, this approach does not work for the Python API because enums
are converted to integers. The four C++ overloads:
```cpp
GetValueForVariablePath(const char *);
GetValueForVariablePath(const char *, lldb::DILMode);
GetValueForVariablePath(const char *, DynamicValueType);
GetValueForVariablePath(const char *, DynamicValueType, lldb::DILMode mode);
```
would appear in python as:
```py
GetValueForVariablePath(str)
GetValueForVariablePath(str, int)
GetValueForVariablePath(str, int)
GetValueForVariablePath(str, int, int)
```

As a result, there is no way to distinguish between `lldb::DILMode` and
`lldb::DynamicValueType` when they are passed as the second parameter.
Existing test did not catch this because there is not test covering
`GetValueForVariablePath(const char *, DynamicValueType)`).

Instead I added an new function called
```cpp
GetValueForVariablePathWithMode(const char*, lldb::DILMode)
GetValueForVariablePathWithMode(const char*, lldb::DILMode, DynamicValueType)
```
and a python helper.
```python
class SBFrame:
    def var_with_mode(self, var_path: str, mode: int, use_dynamic: int, /):
        ...
```

mirroring the existing `SBFrame.var` helper function.

Added: 
    

Modified: 
    lldb/bindings/interface/SBFrameExtensions.i
    lldb/include/lldb/API/SBFrame.h
    lldb/source/API/SBFrame.cpp
    
lldb/test/API/commands/frame/var-dil/basics/AddressOf/TestFrameVarDILAddressOf.py
    
lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py
    
lldb/test/API/commands/frame/var-dil/basics/MemberOf/TestFrameVarDILMemberOf.py
    
lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py
    
lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
    lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
    lldb/test/API/commands/frame/var-dil/expr/Casts/TestFrameVarDILCast.py
    lldb/test/API/functionalities/var_path/TestVarPath.py
    lldb/test/API/functionalities/var_path/main.cpp
    lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
    lldb/tools/lldb-dap/SourceBreakpoint.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/interface/SBFrameExtensions.i 
b/lldb/bindings/interface/SBFrameExtensions.i
index 0c79b98b290f2..64ca132d159f5 100644
--- a/lldb/bindings/interface/SBFrameExtensions.i
+++ b/lldb/bindings/interface/SBFrameExtensions.i
@@ -40,10 +40,17 @@ STRING_EXTENSION_OUTSIDE(SBFrame)
         def get_statics(self):
             return self.GetVariables(False,False,True,False)
 
-        def var(self, var_expr_path):
+        def var(self, var_expr_path, use_dynamic=None):
             '''Calls through to lldb.SBFrame.GetValueForVariablePath() and 
returns
             a value that represents the variable expression path'''
-            return self.GetValueForVariablePath(var_expr_path)
+            if use_dynamic is None:
+                return self.GetValueForVariablePath(var_expr_path)
+            return self.GetValueForVariablePath(var_expr_path, use_dynamic)
+        
+        def var_with_mode(self, var_path: str, mode: int, use_dynamic = None, 
/):
+            if use_dynamic is None:
+                return self.GetValueForVariablePathWithMode(var_path, mode)
+            return self.GetValueForVariablePathWithMode(var_path, mode, 
use_dynamic)
 
         def get_registers_access(self):
             class registers_access(object):

diff  --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h
index 7094ce3ad8fb7..4d67ac74eab12 100644
--- a/lldb/include/lldb/API/SBFrame.h
+++ b/lldb/include/lldb/API/SBFrame.h
@@ -182,16 +182,19 @@ 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::DILMode mode = lldb::eDILModeFull);
+  lldb::SBValue GetValueForVariablePath(const char *var_path,
+                                        DynamicValueType use_dynamic);
 
   /// The version that doesn't supply a 'use_dynamic' value will use the
   /// target's default.
-  lldb::SBValue
-  GetValueForVariablePath(const char *var_path,
-                          lldb::DILMode mode = lldb::eDILModeFull);
+  lldb::SBValue GetValueForVariablePath(const char *var_path);
+
+  lldb::SBValue GetValueForVariablePathWithMode(const char *var_path,
+                                                lldb::DILMode mode,
+                                                DynamicValueType use_dynamic);
+
+  lldb::SBValue GetValueForVariablePathWithMode(const char *var_path,
+                                                lldb::DILMode mode);
 
   /// Find variables, register sets, registers, or persistent variables using
   /// the frame as the scope.

diff  --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index 9158685f78c04..6debaa12dcfe6 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -365,8 +365,7 @@ void SBFrame::Clear() {
   m_opaque_sp->Clear();
 }
 
-lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
-                                               lldb::DILMode mode) {
+lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path) {
   LLDB_INSTRUMENT_VA(this, var_path);
 
   SBValue sb_value;
@@ -380,14 +379,13 @@ 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, mode);
+    sb_value = GetValueForVariablePath(var_path, use_dynamic);
   }
   return sb_value;
 }
 
 lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
-                                               DynamicValueType use_dynamic,
-                                               lldb::DILMode mode) {
+                                               DynamicValueType use_dynamic) {
   LLDB_INSTRUMENT_VA(this, var_path, use_dynamic);
 
   SBValue sb_value;
@@ -402,6 +400,55 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char 
*var_path,
     return sb_value;
   }
 
+  if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+    VariableSP var_sp;
+    Status error;
+    ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
+        var_path, eNoDynamicValues,
+        StackFrame::eExpressionPathOptionCheckPtrVsMember |
+            StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+        var_sp, error, lldb::eDILModeFull));
+    sb_value.SetSP(value_sp, use_dynamic);
+  }
+  return sb_value;
+}
+
+lldb::SBValue SBFrame::GetValueForVariablePathWithMode(const char *var_path,
+                                                       lldb::DILMode mode) {
+  LLDB_INSTRUMENT_VA(this, var_path, mode);
+
+  SBValue sb_value;
+  llvm::Expected<StoppedExecutionContext> exe_ctx =
+      GetStoppedExecutionContext(m_opaque_sp);
+  if (!exe_ctx) {
+    LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+    return sb_value;
+  }
+
+  if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+    lldb::DynamicValueType use_dynamic =
+        frame->CalculateTarget()->GetPreferDynamicValue();
+    sb_value = GetValueForVariablePathWithMode(var_path, mode, use_dynamic);
+  }
+  return sb_value;
+}
+
+lldb::SBValue SBFrame::GetValueForVariablePathWithMode(
+    const char *var_path, lldb::DILMode mode, DynamicValueType use_dynamic) {
+  LLDB_INSTRUMENT_VA(this, var_path, mode, use_dynamic);
+
+  SBValue sb_value;
+  if (var_path == nullptr || var_path[0] == '\0') {
+    return sb_value;
+  }
+
+  llvm::Expected<StoppedExecutionContext> exe_ctx =
+      GetStoppedExecutionContext(m_opaque_sp);
+  if (!exe_ctx) {
+    LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+    return sb_value;
+  }
+
   if (StackFrame *frame = exe_ctx->GetFramePtr()) {
     VariableSP var_sp;
     Status error;

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 bfe29370b4704..4d401dadbe064 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
@@ -39,7 +39,7 @@ def test_frame_var(self):
 
         # 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)
+        simple = frame.GetValueForVariablePathWithMode("&x", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("&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 6f3bbfb970aa4..d0477ac846f70 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
@@ -89,10 +89,19 @@ def test_subscript(self):
 
         # 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)
+        simple = frame.GetValueForVariablePathWithMode(
+            "int_arr[0]", lldb.eDILModeSimple
+        )
+        simple_other = frame.var_with_mode("int_arr[0]", lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode(
+            "int_arr[0]", lldb.eDILModeLegacy
+        )
+        legacy_other = frame.var_with_mode("int_arr[0]", lldb.eDILModeLegacy)
+
         self.assertFailure(simple.GetError())
+        self.assertFailure(simple_other.GetError())
         self.assertSuccess(legacy.GetError())
+        self.assertSuccess(legacy_other.GetError())
 
     def test_subscript_synthetic(self):
         self.build()

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 d37ce0bbc4201..91ec777a5d2e4 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
@@ -52,13 +52,13 @@ def test_frame_var(self):
 
         # 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)
+        simple = frame.GetValueForVariablePathWithMode("s.x", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("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)
+        simple = frame.GetValueForVariablePathWithMode("sp->x", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("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 e18e18e146a46..0fd7534e07fc6 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
@@ -49,7 +49,7 @@ def test_frame_var(self):
 
         # 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)
+        simple = frame.GetValueForVariablePathWithMode("*p_int0", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("*p_int0", 
lldb.eDILModeLegacy)
         self.assertFailure(simple.GetError())
         self.assertSuccess(legacy.GetError())

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index 7729c1ce23d7d..94268ecf46b27 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -169,9 +169,9 @@ def test_arithmetic(self):
 
         # Check that binary * is allowed only in full mode
         frame = thread.GetFrameAtIndex(0)
-        simple = frame.GetValueForVariablePath("x * 2", lldb.eDILModeSimple)
-        legacy = frame.GetValueForVariablePath("x * 2", lldb.eDILModeLegacy)
-        full = frame.GetValueForVariablePath("x * 2", lldb.eDILModeFull)
+        simple = frame.GetValueForVariablePathWithMode("x * 2", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("x * 2", 
lldb.eDILModeLegacy)
+        full = frame.GetValueForVariablePathWithMode("x * 2", 
lldb.eDILModeFull)
         self.assertFailure(simple.GetError())
         self.assertFailure(legacy.GetError())
         self.assertSuccess(full.GetError())

diff  --git 
a/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py 
b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
index 5ce2954893f9f..abd5091b28fb2 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
@@ -107,9 +107,13 @@ def test_bitwise(self):
 
         # Check that bitwise & is allowed only in full mode
         frame = thread.GetFrameAtIndex(0)
-        simple = frame.GetValueForVariablePath("i64 & 1", lldb.eDILModeSimple)
-        legacy = frame.GetValueForVariablePath("i64 & 1", lldb.eDILModeLegacy)
-        full = frame.GetValueForVariablePath("i64 & 1", lldb.eDILModeFull)
+        simple = frame.GetValueForVariablePathWithMode("i64 & 1", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("i64 & 1", 
lldb.eDILModeLegacy)
+        legacy_other = frame.var_with_mode("i64 & 1", lldb.eDILModeLegacy)
+        full = frame.GetValueForVariablePathWithMode("i64 & 1", 
lldb.eDILModeFull)
+        full_other = frame.var_with_mode("i64 & 1", lldb.eDILModeFull)
         self.assertFailure(simple.GetError())
         self.assertFailure(legacy.GetError())
+        self.assertFailure(legacy_other.GetError())
         self.assertSuccess(full.GetError())
+        self.assertSuccess(full_other.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 7179a9acac441..17a083c19a525 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
@@ -303,8 +303,8 @@ def test_type_cast(self):
 
         # 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)
+        simple = frame.GetValueForVariablePathWithMode("(char)a", 
lldb.eDILModeSimple)
+        legacy = frame.GetValueForVariablePathWithMode("(char)a", 
lldb.eDILModeLegacy)
         self.assertFailure(simple.GetError())
         self.assertFailure(legacy.GetError())
 

diff  --git a/lldb/test/API/functionalities/var_path/TestVarPath.py 
b/lldb/test/API/functionalities/var_path/TestVarPath.py
index 53c45f57f517d..873f659acfcf7 100644
--- a/lldb/test/API/functionalities/var_path/TestVarPath.py
+++ b/lldb/test/API/functionalities/var_path/TestVarPath.py
@@ -100,6 +100,8 @@ def do_test(self):
         self.verify_point(frame, "pt_ptr[0]", "Point", 3030, 4040)
         self.verify_point(frame, "pt_ptr[1]", "Point", 5050, 6060)
         # Test arrays
+        v_helper = frame.var("points")
+        self.assertSuccess(v_helper.GetError(), "Make sure we find 'points'")
         v = frame.GetValueForVariablePath("points")
         self.assertSuccess(v.GetError(), "Make sure we find 'points'")
         self.verify_point(frame, "points[0]", "Point", 1010, 2020)
@@ -121,3 +123,72 @@ def do_test(self):
             self.assertTrue(
                 v.GetError().Fail(), "Make sure we don't find 
'pt_sp->not_valid_child'"
             )
+
+    @expectedFailureAll(
+        oslist=["windows"],
+        bugnumber="https://github.com/llvm/llvm-project/issues/25037";,
+    )
+    def test_frame_var_use_dynamic(self):
+        """Test `SBFrame.GetValueForVariablePath` return the current value and 
variable type."""
+        self.build()
+        (_, _, thread, _) = lldbutil.run_to_source_breakpoint(
+            self, "// Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+        frame: lldb.SBFrame = thread.GetFrameAtIndex(0)
+
+        # Verify concrete types.
+        concrete = [
+            ("shape", "Shape"),
+            ("shape_ref", "Shape &"),
+            ("shape_ptr", "Shape *"),
+            ("circle", "Circle"),
+            ("circle_ref", "Circle &"),
+            ("circle_ptr", "Circle *"),
+        ]
+        for name, expected_type in concrete:
+            for dyn_val in (lldb.eNoDynamicValues, lldb.eDynamicDontRunTarget):
+                val: lldb.SBValue = frame.GetValueForVariablePath(name, 
dyn_val)
+                self.assertSuccess(val.GetError(), f"Make sure we find 
{name!r}")
+                self.assertEqual(val.GetTypeName(), expected_type)
+
+                # Test the helper.
+                val: lldb.SBValue = frame.var(name, dyn_val)
+                self.assertTrue(val.GetError().Success(), f"Make sure we find 
{name!r}")
+                self.assertEqual(val.GetTypeName(), expected_type)
+
+        # Verify dynamic types.
+        polymorphic = [
+            ("circle_as_shape_ref", "Shape &", "Circle &"),
+            ("circle_as_shape_ptr", "Shape *", "Circle *"),
+            ("circle_as_drawable_ref", "Drawable &", "Circle &"),
+            ("circle_as_drawable_ptr", "Drawable *", "Circle *"),
+        ]
+        for name, static_type, dynamic_type in polymorphic:
+            static = frame.GetValueForVariablePath(name, lldb.eNoDynamicValues)
+            static_helper: lldb.SBValue = frame.var(name, 
lldb.eNoDynamicValues)
+            for val in (static, static_helper):
+                self.assertSuccess(val.GetError(), f"find {name!r} (static)")
+                self.assertEqual(static_type, val.GetTypeName())
+                self.assertNotIn("Circle", val.GetTypeName())
+                self.assertFalse(
+                    val.GetChildMemberWithName("circle_val").IsValid(),
+                    f"{name!r} should not expose circle_val under 
eNoDynamicValues",
+                )
+
+            dynamic = frame.GetValueForVariablePath(name, 
lldb.eDynamicDontRunTarget)
+            dynamic_helper: lldb.SBValue = frame.var(name, 
lldb.eDynamicDontRunTarget)
+            for val in (dynamic, dynamic_helper):
+                self.assertSuccess(val.GetError(), f"find {name!r} (dynamic)")
+                self.assertEqual(
+                    dynamic_type,
+                    val.GetTypeName(),
+                    f"'{name}' should resolve to Circle under 
eDynamicDontRunTarget",
+                )
+                circle_val = val.GetChildMemberWithName("circle_val")
+                self.assertTrue(
+                    circle_val.IsValid(),
+                    f"{name!r} should expose circle_val under 
eDynamicDontRunTarget",
+                )
+
+                # Verify we can fetch the child from the static type.
+                self.assertEqual(circle_val.GetValueAsSigned(), 20)

diff  --git a/lldb/test/API/functionalities/var_path/main.cpp 
b/lldb/test/API/functionalities/var_path/main.cpp
index 0ea19cfcfea53..daf1d95114657 100644
--- a/lldb/test/API/functionalities/var_path/main.cpp
+++ b/lldb/test/API/functionalities/var_path/main.cpp
@@ -1,5 +1,23 @@
 #include <memory>
 
+class Shape {
+public:
+  virtual ~Shape() = default;
+  int shape_val = 10;
+};
+
+class Drawable {
+public:
+  virtual ~Drawable() = default;
+  virtual void draw() = 0;
+};
+
+class Circle : public Shape, public Drawable {
+public:
+  int circle_val = 20;
+  void draw() override {}
+};
+
 struct Point {
   int x, y;
 };
@@ -10,6 +28,21 @@ int main() {
   Point *pt_ptr = &points[1];
   Point &pt_ref = pt;
   std::shared_ptr<Point> pt_sp(new Point{111,222});
+
+  Shape shape{};
+  Shape &shape_ref = shape;
+  Shape *shape_ptr = &shape;
+
+  Circle circle{};
+  Circle &circle_ref = circle;
+  Circle *circle_ptr = &circle;
+
+  Shape &circle_as_shape_ref = circle;
+  Shape *circle_as_shape_ptr = &circle;
+
+  Drawable &circle_as_drawable_ref = circle;
+  Drawable *circle_as_drawable_ptr = &circle;
+
   return 0; // Set a breakpoint here
 }
 

diff  --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
index 7537eca72ec25..878905ed5adc2 100644
--- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp
@@ -55,8 +55,8 @@ static lldb::SBValue 
EvaluateVariableExpression(lldb::SBTarget &target,
     // Check if it is a variable or an expression path for a variable. i.e.
     // 'foo->bar' finds the 'bar' variable. It is more reliable than the
     // expression parser in many cases and it is faster.
-    value = frame.GetValueForVariablePath(
-        expression_cstr, lldb::eDynamicDontRunTarget, lldb::eDILModeLegacy);
+    value = frame.GetValueForVariablePathWithMode(
+        expression_cstr, lldb::eDILModeLegacy, lldb::eDynamicDontRunTarget);
     if (value || !run_as_expression)
       return value;
 

diff  --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp 
b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
index 4cec1a927f618..fbc995e8a6e3f 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
@@ -399,8 +399,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::eDILModeLegacy);
+      lldb::SBValue value = frame.GetValueForVariablePathWithMode(
+          expr, lldb::eDILModeLegacy, lldb::eDynamicDontRunTarget);
       if (value.GetError().Fail())
         value = frame.EvaluateExpression(expr);
       output += VariableDescription(


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to