diff options
| author | Tonko SabolĨec <tonkosi123@gmail.com> | 2022-10-12 11:46:23 +0000 |
|---|---|---|
| committer | Andy Yankovsky <weratt@gmail.com> | 2022-10-12 12:08:57 +0000 |
| commit | 0205aa4a02570dfeda5807f66756ebdbb102744b (patch) | |
| tree | f29df407f3a7e4d2be9f12716d34021a832e50a4 /lldb/test/API/python_api | |
| parent | b781ef890fcf4d4fdf1734fa437099bdf5d8d6fc (diff) | |
| download | llvm-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/Makefile | 3 | ||||
| -rw-r--r-- | lldb/test/API/python_api/expression_path/TestExpressionPath.py | 119 | ||||
| -rw-r--r-- | lldb/test/API/python_api/expression_path/main.cpp | 34 |
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 |
