aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/API/python_api
diff options
context:
space:
mode:
authorTonko SabolĨec <tonkosi123@gmail.com>2022-10-12 11:46:23 +0000
committerAndy Yankovsky <weratt@gmail.com>2022-10-12 12:08:57 +0000
commit0205aa4a02570dfeda5807f66756ebdbb102744b (patch)
treef29df407f3a7e4d2be9f12716d34021a832e50a4 /lldb/test/API/python_api
parentb781ef890fcf4d4fdf1734fa437099bdf5d8d6fc (diff)
downloadllvm-0205aa4a02570dfeda5807f66756ebdbb102744b.zip
llvm-0205aa4a02570dfeda5807f66756ebdbb102744b.tar.gz
llvm-0205aa4a02570dfeda5807f66756ebdbb102744b.tar.bz2
[lldb] Fix member access in GetExpressionPath
This change fixes two issues in ValueObject::GetExpressionPath method: 1. Accessing members of struct references used to produce expression paths such as "str.&str.member" (instead of the expected "str.member"). This is fixed by assigning the flag tha the child value is a dereference when calling Dereference() on references and adjusting logic in expression path creation. 2. If the parent of member access is dereference, the produced expression path was "*(ptr).member". This is incorrect, since it dereferences the member instead of the pointer. This is fixed by wrapping dereference expression into parenthesis, resulting with "(*ptr).member". Reviewed By: werat, clayborg Differential Revision: https://reviews.llvm.org/D132734
Diffstat (limited to 'lldb/test/API/python_api')
-rw-r--r--lldb/test/API/python_api/expression_path/Makefile3
-rw-r--r--lldb/test/API/python_api/expression_path/TestExpressionPath.py119
-rw-r--r--lldb/test/API/python_api/expression_path/main.cpp34
3 files changed, 156 insertions, 0 deletions
diff --git a/lldb/test/API/python_api/expression_path/Makefile b/lldb/test/API/python_api/expression_path/Makefile
new file mode 100644
index 0000000..99998b2
--- /dev/null
+++ b/lldb/test/API/python_api/expression_path/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/python_api/expression_path/TestExpressionPath.py b/lldb/test/API/python_api/expression_path/TestExpressionPath.py
new file mode 100644
index 0000000..bc81065
--- /dev/null
+++ b/lldb/test/API/python_api/expression_path/TestExpressionPath.py
@@ -0,0 +1,119 @@
+"""Test that SBFrame::GetExpressionPath construct valid expressions"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class SBValueGetExpressionPathTest(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def path(self, value):
+ """Constructs the expression path given the SBValue"""
+ if not value:
+ return None
+ stream = lldb.SBStream()
+ if not value.GetExpressionPath(stream):
+ return None
+ return stream.GetData()
+
+ def test_expression_path(self):
+ """Test that SBFrame::GetExpressionPath construct valid expressions"""
+ self.build()
+ self.setTearDownCleanup()
+
+ exe = self.getBuildArtifact("a.out")
+
+ # Create the target
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ # Set the breakpoints
+ breakpoint = target.BreakpointCreateBySourceRegex(
+ 'Set breakpoint here', lldb.SBFileSpec("main.cpp"))
+ self.assertTrue(breakpoint.GetNumLocations() > 0, VALID_BREAKPOINT)
+
+ # Launch the process, and do not stop at the entry point.
+ process = target.LaunchSimple(
+ None, None, self.get_process_working_directory())
+
+ self.assertTrue(process, PROCESS_IS_VALID)
+
+ # Frame #0 should be at our breakpoint.
+ threads = lldbutil.get_threads_stopped_at_breakpoint(
+ process, breakpoint)
+
+ self.assertEquals(len(threads), 1)
+ self.thread = threads[0]
+ self.frame = self.thread.frames[0]
+ self.assertTrue(self.frame, "Frame 0 is valid.")
+
+ # Find "b" variables in frame
+ b = self.frame.FindVariable("b")
+ bp = self.frame.FindVariable("b_ptr")
+ br = self.frame.FindVariable("b_ref")
+ bpr = self.frame.FindVariable("b_ptr_ref")
+ # Check expression paths
+ self.assertEqual(self.path(b), "b")
+ self.assertEqual(self.path(bp), "b_ptr")
+ self.assertEqual(self.path(br), "b_ref")
+ self.assertEqual(self.path(bpr), "b_ptr_ref")
+
+ # Dereference "b" pointers
+ bp_deref = bp.Dereference()
+ bpr_deref = bpr.Dereference() # a pointer
+ bpr_deref2 = bpr_deref.Dereference() # two Dereference() calls to get object
+ # Check expression paths
+ self.assertEqual(self.path(bp_deref), "*b_ptr")
+ self.assertEqual(self.path(bpr_deref), "b_ptr_ref")
+ self.assertEqual(self.path(bpr_deref2), "*b_ptr_ref")
+
+ # Access "b" members and check expression paths
+ self.assertEqual(self.path(b.GetChildMemberWithName("x")), "b.x")
+ self.assertEqual(self.path(bp.GetChildMemberWithName("x")), "b_ptr->x")
+ self.assertEqual(self.path(br.GetChildMemberWithName("x")), "b_ref.x")
+ self.assertEqual(self.path(bp_deref.GetChildMemberWithName("x")), "(*b_ptr).x")
+ self.assertEqual(self.path(bpr_deref.GetChildMemberWithName("x")), "b_ptr_ref->x")
+ self.assertEqual(self.path(bpr_deref2.GetChildMemberWithName("x")), "(*b_ptr_ref).x")
+ # TODO: Uncomment once accessing members on pointer references is supported.
+ # self.assertEqual(self.path(bpr.GetChildMemberWithName("x")), "b_ptr_ref->x")
+
+ # Try few expressions with multiple member access
+ bp_ar_x = bp.GetChildMemberWithName("a_ref").GetChildMemberWithName("x")
+ br_ar_y = br.GetChildMemberWithName("a_ref").GetChildMemberWithName("y")
+ self.assertEqual(self.path(bp_ar_x), "b_ptr->a_ref.x")
+ self.assertEqual(self.path(br_ar_y), "b_ref.a_ref.y")
+ bpr_deref_apr_deref = bpr_deref.GetChildMemberWithName("a_ptr_ref").Dereference()
+ bpr_deref_apr_deref2 = bpr_deref_apr_deref.Dereference()
+ self.assertEqual(self.path(bpr_deref_apr_deref), "b_ptr_ref->a_ptr_ref")
+ self.assertEqual(self.path(bpr_deref_apr_deref2), "*b_ptr_ref->a_ptr_ref")
+ bpr_deref_apr_deref_x = bpr_deref_apr_deref.GetChildMemberWithName("x")
+ bpr_deref_apr_deref2_x = bpr_deref_apr_deref2.GetChildMemberWithName("x")
+ self.assertEqual(self.path(bpr_deref_apr_deref_x), "b_ptr_ref->a_ptr_ref->x")
+ self.assertEqual(self.path(bpr_deref_apr_deref2_x), "(*b_ptr_ref->a_ptr_ref).x")
+
+ # Find "c" variables in frame
+ c = self.frame.FindVariable("c")
+ cp = self.frame.FindVariable("c_ptr")
+ cr = self.frame.FindVariable("c_ref")
+ cpr = self.frame.FindVariable("c_ptr_ref")
+ # Dereference pointers
+ cp_deref = cp.Dereference()
+ cpr_deref = cpr.Dereference() # a pointer
+ cpr_deref2 = cpr_deref.Dereference() # two Dereference() calls to get object
+ # Check expression paths
+ self.assertEqual(self.path(cp_deref), "*c_ptr")
+ self.assertEqual(self.path(cpr_deref), "c_ptr_ref")
+ self.assertEqual(self.path(cpr_deref2), "*c_ptr_ref")
+
+ # Access members on "c" variables and check expression paths
+ self.assertEqual(self.path(c.GetChildMemberWithName("x")), "c.x")
+ self.assertEqual(self.path(cp.GetChildMemberWithName("x")), "c_ptr->x")
+ self.assertEqual(self.path(cr.GetChildMemberWithName("x")), "c_ref.x")
+ self.assertEqual(self.path(cp_deref.GetChildMemberWithName("x")), "(*c_ptr).x")
+ self.assertEqual(self.path(cpr_deref.GetChildMemberWithName("x")), "c_ptr_ref->x")
+ self.assertEqual(self.path(cpr_deref2.GetChildMemberWithName("x")), "(*c_ptr_ref).x")
+ # TODO: Uncomment once accessing members on pointer references is supported.
+ # self.assertEqual(self.path(cpr.GetChildMemberWithName("x")), "c_ptr_ref->x") \ No newline at end of file
diff --git a/lldb/test/API/python_api/expression_path/main.cpp b/lldb/test/API/python_api/expression_path/main.cpp
new file mode 100644
index 0000000..522022b
--- /dev/null
+++ b/lldb/test/API/python_api/expression_path/main.cpp
@@ -0,0 +1,34 @@
+struct StructA {
+ int x;
+ int y;
+};
+
+struct StructB {
+ int x;
+ StructA &a_ref;
+ StructA *&a_ptr_ref;
+};
+
+struct StructC : public StructB {
+ int y;
+
+ StructC(int x, StructA &a_ref, StructA *&a_ref_ptr, int y)
+ : StructB{x, a_ref, a_ref_ptr}, y(y) {}
+};
+
+int main() {
+ StructA a{1, 2};
+ StructA *a_ptr = &a;
+
+ StructB b{3, a, a_ptr};
+ StructB *b_ptr = &b;
+ StructB &b_ref = b;
+ StructB *&b_ptr_ref = b_ptr;
+
+ StructC c(4, a, a_ptr, 5);
+ StructC *c_ptr = &c;
+ StructC &c_ref = c;
+ StructC *&c_ptr_ref = c_ptr;
+
+ return 0; // Set breakpoint here
+} \ No newline at end of file