xref: /llvm-project/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py (revision dd5d73007240712957f2b633f795d9965afaadd6)
1"""
2Use lldb Python API to test dynamic values in C++
3"""
4
5
6import lldb
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11
12class DynamicValueTestCase(TestBase):
13    def setUp(self):
14        # Call super's setUp().
15        TestBase.setUp(self)
16
17        # Find the line number to break for main.c.
18
19        self.do_something_line = line_number(
20            "pass-to-base.cpp", "// Break here in doSomething."
21        )
22        self.main_first_call_line = line_number(
23            "pass-to-base.cpp",
24            "// Break here and get real addresses of myB and otherB.",
25        )
26        self.main_second_call_line = line_number(
27            "pass-to-base.cpp", "// Break here and get real address of reallyA."
28        )
29
30    @add_test_categories(["pyapi"])
31    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24663")
32    def test_get_dynamic_vals(self):
33        """Test fetching C++ dynamic values from pointers & references."""
34        self.build()
35        exe = self.getBuildArtifact("a.out")
36
37        # Create a target from the debugger.
38
39        target = self.dbg.CreateTarget(exe)
40        self.assertTrue(target, VALID_TARGET)
41
42        # Set up our breakpoints:
43
44        do_something_bpt = target.BreakpointCreateByLocation(
45            "pass-to-base.cpp", self.do_something_line
46        )
47        self.assertTrue(do_something_bpt, VALID_BREAKPOINT)
48
49        first_call_bpt = target.BreakpointCreateByLocation(
50            "pass-to-base.cpp", self.main_first_call_line
51        )
52        self.assertTrue(first_call_bpt, VALID_BREAKPOINT)
53
54        second_call_bpt = target.BreakpointCreateByLocation(
55            "pass-to-base.cpp", self.main_second_call_line
56        )
57        self.assertTrue(second_call_bpt, VALID_BREAKPOINT)
58
59        # Now launch the process, and do not stop at the entry point.
60        process = target.LaunchSimple(None, None, self.get_process_working_directory())
61
62        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
63
64        threads = lldbutil.get_threads_stopped_at_breakpoint(process, first_call_bpt)
65        self.assertEqual(len(threads), 1)
66        thread = threads[0]
67
68        frame = thread.GetFrameAtIndex(0)
69
70        # Now find the dynamic addresses of myB and otherB so we can compare them
71        # with the dynamic values we get in doSomething:
72
73        use_dynamic = lldb.eDynamicCanRunTarget
74        no_dynamic = lldb.eNoDynamicValues
75
76        myB = frame.FindVariable("myB", no_dynamic)
77        self.assertTrue(myB)
78        myB_loc = int(myB.GetLocation(), 16)
79
80        otherB = frame.FindVariable("otherB", no_dynamic)
81        self.assertTrue(otherB)
82        otherB_loc = int(otherB.GetLocation(), 16)
83
84        # Okay now run to doSomething:
85
86        threads = lldbutil.continue_to_breakpoint(process, do_something_bpt)
87        self.assertEqual(len(threads), 1)
88        thread = threads[0]
89
90        frame = thread.GetFrameAtIndex(0)
91
92        # Get "this" using FindVariable:
93
94        this_static = frame.FindVariable("this", no_dynamic)
95        this_dynamic = frame.FindVariable("this", use_dynamic)
96        self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc)
97
98        # Now make sure that the "GetDynamicValue" works:
99        # This doesn't work currently because we can't get dynamic values from
100        # ConstResult objects.
101        fetched_dynamic_value = this_static.GetDynamicValue(use_dynamic)
102        self.examine_value_object_of_this_ptr(
103            this_static, fetched_dynamic_value, myB_loc
104        )
105
106        # And conversely that the GetDynamicValue() interface also works:
107        fetched_static_value = this_dynamic.GetStaticValue()
108        self.examine_value_object_of_this_ptr(
109            fetched_static_value, this_dynamic, myB_loc
110        )
111
112        # Get "this" using FindValue, make sure that works too:
113        this_static = frame.FindValue(
114            "this", lldb.eValueTypeVariableArgument, no_dynamic
115        )
116        this_dynamic = frame.FindValue(
117            "this", lldb.eValueTypeVariableArgument, use_dynamic
118        )
119        self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc)
120
121        # Get "this" using the EvaluateExpression:
122        this_static = frame.EvaluateExpression("this", False)
123        this_dynamic = frame.EvaluateExpression("this", True)
124        self.examine_value_object_of_this_ptr(this_static, this_dynamic, myB_loc)
125
126        # The "frame var" code uses another path to get into children, so let's
127        # make sure that works as well:
128
129        self.expect(
130            "frame var -d run-target --ptr-depth=2 --show-types anotherA.m_client_A",
131            "frame var finds its way into a child member",
132            patterns=["\(B \*\)"],
133        )
134
135        # Now make sure we also get it right for a reference as well:
136
137        anotherA_static = frame.FindVariable("anotherA", False)
138        self.assertTrue(anotherA_static)
139        anotherA_static_addr = int(anotherA_static.GetValue(), 16)
140
141        anotherA_dynamic = frame.FindVariable("anotherA", True)
142        self.assertTrue(anotherA_dynamic)
143        anotherA_dynamic_addr = int(anotherA_dynamic.GetValue(), 16)
144        anotherA_dynamic_typename = anotherA_dynamic.GetTypeName()
145        self.assertNotEqual(anotherA_dynamic_typename.find("B"), -1)
146
147        self.assertLess(anotherA_dynamic_addr, anotherA_static_addr)
148
149        anotherA_m_b_value_dynamic = anotherA_dynamic.GetChildMemberWithName(
150            "m_b_value", True
151        )
152        self.assertTrue(anotherA_m_b_value_dynamic)
153        anotherA_m_b_val = int(anotherA_m_b_value_dynamic.GetValue(), 10)
154        self.assertEqual(anotherA_m_b_val, 300)
155
156        anotherA_m_b_value_static = anotherA_static.GetChildMemberWithName(
157            "m_b_value", True
158        )
159        self.assertFalse(anotherA_m_b_value_static)
160
161        # Okay, now continue again, and when we hit the second breakpoint in
162        # main
163
164        threads = lldbutil.continue_to_breakpoint(process, second_call_bpt)
165        self.assertEqual(len(threads), 1)
166        thread = threads[0]
167
168        frame = thread.GetFrameAtIndex(0)
169        reallyA_value = frame.FindVariable("reallyA", False)
170        self.assertTrue(reallyA_value)
171        reallyA_loc = int(reallyA_value.GetLocation(), 16)
172
173        # Continue to doSomething again, and make sure we get the right value for anotherA,
174        # which this time around is just an "A".
175
176        threads = lldbutil.continue_to_breakpoint(process, do_something_bpt)
177        self.assertEqual(len(threads), 1)
178        thread = threads[0]
179
180        frame = thread.GetFrameAtIndex(0)
181        anotherA_value = frame.FindVariable("anotherA", True)
182        self.assertTrue(anotherA_value)
183        anotherA_loc = int(anotherA_value.GetValue(), 16)
184        self.assertEqual(anotherA_loc, reallyA_loc)
185        self.assertEqual(anotherA_value.GetTypeName().find("B"), -1)
186
187        # Finally do the same with a B in an anonymous namespace.
188        threads = lldbutil.continue_to_breakpoint(process, do_something_bpt)
189        self.assertEqual(len(threads), 1)
190        thread = threads[0]
191
192        frame = thread.GetFrameAtIndex(0)
193        anotherA_value = frame.FindVariable("anotherA", use_dynamic)
194        self.assertTrue(anotherA_value)
195        self.assertIn("B", anotherA_value.GetTypeName())
196        anon_b_value = anotherA_value.GetChildMemberWithName("m_anon_b_value")
197        self.assertTrue(anon_b_value)
198        self.assertEqual(anon_b_value.GetValueAsSigned(), 47)
199
200    def examine_value_object_of_this_ptr(
201        self, this_static, this_dynamic, dynamic_location
202    ):
203        # Get "this" as its static value
204        self.assertTrue(this_static)
205        this_static_loc = int(this_static.GetValue(), 16)
206
207        # Get "this" as its dynamic value
208
209        self.assertTrue(this_dynamic)
210        this_dynamic_typename = this_dynamic.GetTypeName()
211        self.assertNotEqual(this_dynamic_typename.find("B"), -1)
212        this_dynamic_loc = int(this_dynamic.GetValue(), 16)
213
214        # Make sure we got the right address for "this"
215
216        self.assertEqual(this_dynamic_loc, dynamic_location)
217
218        # And that the static address is greater than the dynamic one
219
220        self.assertGreater(this_static_loc, this_dynamic_loc)
221
222        # Now read m_b_value which is only in the dynamic value:
223
224        use_dynamic = lldb.eDynamicCanRunTarget
225        no_dynamic = lldb.eNoDynamicValues
226
227        this_dynamic_m_b_value = this_dynamic.GetChildMemberWithName(
228            "m_b_value", use_dynamic
229        )
230        self.assertTrue(this_dynamic_m_b_value)
231
232        m_b_value = int(this_dynamic_m_b_value.GetValue(), 0)
233        self.assertEqual(m_b_value, 10)
234
235        # Make sure it is not in the static version
236
237        this_static_m_b_value = this_static.GetChildMemberWithName(
238            "m_b_value", no_dynamic
239        )
240        self.assertFalse(this_static_m_b_value)
241
242        # Okay, now let's make sure that we can get the dynamic type of a child
243        # element:
244
245        contained_auto_ptr = this_dynamic.GetChildMemberWithName(
246            "m_client_A", use_dynamic
247        )
248        self.assertTrue(contained_auto_ptr)
249        contained_b = contained_auto_ptr.GetChildMemberWithName("_M_ptr", use_dynamic)
250        if not contained_b:
251            contained_b = contained_auto_ptr.GetChildMemberWithName(
252                "__ptr_", use_dynamic
253            )
254        self.assertTrue(contained_b)
255
256        contained_b_static = contained_auto_ptr.GetChildMemberWithName(
257            "_M_ptr", no_dynamic
258        )
259        if not contained_b_static:
260            contained_b_static = contained_auto_ptr.GetChildMemberWithName(
261                "__ptr_", no_dynamic
262            )
263        self.assertTrue(contained_b_static)
264
265        contained_b_addr = int(contained_b.GetValue(), 16)
266        contained_b_static_addr = int(contained_b_static.GetValue(), 16)
267
268        self.assertLess(contained_b_addr, contained_b_static_addr)
269