1*99451b44SJordan Rupprecht"""
2*99451b44SJordan RupprechtTest lldb data formatter subsystem.
3*99451b44SJordan Rupprecht"""
4*99451b44SJordan Rupprecht
5*99451b44SJordan Rupprechtfrom __future__ import print_function
6*99451b44SJordan Rupprecht
7*99451b44SJordan Rupprecht
8*99451b44SJordan Rupprechtimport lldb
9*99451b44SJordan Rupprechtfrom lldbsuite.test.decorators import *
10*99451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import *
11*99451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil
12*99451b44SJordan Rupprecht
13*99451b44SJordan Rupprecht
14*99451b44SJordan Rupprechtclass PythonSynthDataFormatterTestCase(TestBase):
15*99451b44SJordan Rupprecht
16*99451b44SJordan Rupprecht    def test_with_run_command(self):
17*99451b44SJordan Rupprecht        """Test data formatter commands."""
18*99451b44SJordan Rupprecht        self.build()
19*99451b44SJordan Rupprecht        self.data_formatter_commands()
20*99451b44SJordan Rupprecht
21*99451b44SJordan Rupprecht    def test_rdar10960550_with_run_command(self):
22*99451b44SJordan Rupprecht        """Test data formatter commands."""
23*99451b44SJordan Rupprecht        self.build()
24*99451b44SJordan Rupprecht        self.rdar10960550_formatter_commands()
25*99451b44SJordan Rupprecht
26*99451b44SJordan Rupprecht    def setUp(self):
27*99451b44SJordan Rupprecht        # Call super's setUp().
28*99451b44SJordan Rupprecht        TestBase.setUp(self)
29*99451b44SJordan Rupprecht        # Find the line number to break at.
30*99451b44SJordan Rupprecht        self.line = line_number('main.cpp', '// Set break point at this line.')
31*99451b44SJordan Rupprecht        self.line2 = line_number('main.cpp',
32*99451b44SJordan Rupprecht                                 '// Set cast break point at this line.')
33*99451b44SJordan Rupprecht        self.line3 = line_number(
34*99451b44SJordan Rupprecht            'main.cpp', '// Set second cast break point at this line.')
35*99451b44SJordan Rupprecht
36*99451b44SJordan Rupprecht    def data_formatter_commands(self):
37*99451b44SJordan Rupprecht        """Test using Python synthetic children provider."""
38*99451b44SJordan Rupprecht
39*99451b44SJordan Rupprecht        _, process, thread, _ = lldbutil.run_to_line_breakpoint(
40*99451b44SJordan Rupprecht            self, lldb.SBFileSpec("main.cpp"), self.line)
41*99451b44SJordan Rupprecht
42*99451b44SJordan Rupprecht        # This is the function to remove the custom formats in order to have a
43*99451b44SJordan Rupprecht        # clean slate for the next test case.
44*99451b44SJordan Rupprecht        def cleanup():
45*99451b44SJordan Rupprecht            self.runCmd('type format clear', check=False)
46*99451b44SJordan Rupprecht            self.runCmd('type summary clear', check=False)
47*99451b44SJordan Rupprecht            self.runCmd('type filter clear', check=False)
48*99451b44SJordan Rupprecht            self.runCmd('type synth clear', check=False)
49*99451b44SJordan Rupprecht
50*99451b44SJordan Rupprecht        # Execute the cleanup function during test case tear down.
51*99451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
52*99451b44SJordan Rupprecht
53*99451b44SJordan Rupprecht        # print the f00_1 variable without a synth
54*99451b44SJordan Rupprecht        self.expect("frame variable f00_1",
55*99451b44SJordan Rupprecht                    substrs=['a = 1',
56*99451b44SJordan Rupprecht                             'b = 2',
57*99451b44SJordan Rupprecht                             'r = 34'])
58*99451b44SJordan Rupprecht
59*99451b44SJordan Rupprecht        # now set up the synth
60*99451b44SJordan Rupprecht        self.runCmd("script from fooSynthProvider import *")
61*99451b44SJordan Rupprecht        self.runCmd("type synth add -l fooSynthProvider foo")
62*99451b44SJordan Rupprecht        self.runCmd("type synth add -l wrapfooSynthProvider wrapfoo")
63*99451b44SJordan Rupprecht        self.expect("type synthetic list foo", substrs=['fooSynthProvider'])
64*99451b44SJordan Rupprecht
65*99451b44SJordan Rupprecht        # note that the value of fake_a depends on target byte order
66*99451b44SJordan Rupprecht        if process.GetByteOrder() == lldb.eByteOrderLittle:
67*99451b44SJordan Rupprecht            fake_a_val = 0x02000000
68*99451b44SJordan Rupprecht        else:
69*99451b44SJordan Rupprecht            fake_a_val = 0x00000100
70*99451b44SJordan Rupprecht
71*99451b44SJordan Rupprecht        # check that we get the two real vars and the fake_a variables
72*99451b44SJordan Rupprecht        self.expect(
73*99451b44SJordan Rupprecht            "frame variable f00_1",
74*99451b44SJordan Rupprecht            substrs=[
75*99451b44SJordan Rupprecht                'a = 1',
76*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
77*99451b44SJordan Rupprecht                'r = 34',
78*99451b44SJordan Rupprecht            ])
79*99451b44SJordan Rupprecht
80*99451b44SJordan Rupprecht        # check that we do not get the extra vars
81*99451b44SJordan Rupprecht        self.expect("frame variable f00_1", matching=False,
82*99451b44SJordan Rupprecht                    substrs=['b = 2'])
83*99451b44SJordan Rupprecht
84*99451b44SJordan Rupprecht        # check access to members by name
85*99451b44SJordan Rupprecht        self.expect('frame variable f00_1.fake_a',
86*99451b44SJordan Rupprecht                    substrs=['%d' % fake_a_val])
87*99451b44SJordan Rupprecht
88*99451b44SJordan Rupprecht        # check access to members by index
89*99451b44SJordan Rupprecht        self.expect('frame variable f00_1[1]',
90*99451b44SJordan Rupprecht                    substrs=['%d' % fake_a_val])
91*99451b44SJordan Rupprecht
92*99451b44SJordan Rupprecht        # put synthetic children in summary in several combinations
93*99451b44SJordan Rupprecht        self.runCmd(
94*99451b44SJordan Rupprecht            "type summary add --summary-string \"fake_a=${svar.fake_a}\" foo")
95*99451b44SJordan Rupprecht        self.expect('frame variable f00_1',
96*99451b44SJordan Rupprecht                    substrs=['fake_a=%d' % fake_a_val])
97*99451b44SJordan Rupprecht        self.runCmd(
98*99451b44SJordan Rupprecht            "type summary add --summary-string \"fake_a=${svar[1]}\" foo")
99*99451b44SJordan Rupprecht        self.expect('frame variable f00_1',
100*99451b44SJordan Rupprecht                    substrs=['fake_a=%d' % fake_a_val])
101*99451b44SJordan Rupprecht
102*99451b44SJordan Rupprecht        # clear the summary
103*99451b44SJordan Rupprecht        self.runCmd("type summary delete foo")
104*99451b44SJordan Rupprecht
105*99451b44SJordan Rupprecht        # check that the caching does not span beyond the stopoint
106*99451b44SJordan Rupprecht        self.runCmd("n")
107*99451b44SJordan Rupprecht
108*99451b44SJordan Rupprecht        if process.GetByteOrder() == lldb.eByteOrderLittle:
109*99451b44SJordan Rupprecht            fake_a_val = 0x02000000
110*99451b44SJordan Rupprecht        else:
111*99451b44SJordan Rupprecht            fake_a_val = 0x00000200
112*99451b44SJordan Rupprecht
113*99451b44SJordan Rupprecht        self.expect(
114*99451b44SJordan Rupprecht            "frame variable f00_1",
115*99451b44SJordan Rupprecht            substrs=[
116*99451b44SJordan Rupprecht                'a = 2',
117*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
118*99451b44SJordan Rupprecht                'r = 34',
119*99451b44SJordan Rupprecht            ])
120*99451b44SJordan Rupprecht
121*99451b44SJordan Rupprecht        # check that altering the object also alters fake_a
122*99451b44SJordan Rupprecht        self.runCmd("expr f00_1.a = 280")
123*99451b44SJordan Rupprecht
124*99451b44SJordan Rupprecht        if process.GetByteOrder() == lldb.eByteOrderLittle:
125*99451b44SJordan Rupprecht            fake_a_val = 0x02000001
126*99451b44SJordan Rupprecht        else:
127*99451b44SJordan Rupprecht            fake_a_val = 0x00011800
128*99451b44SJordan Rupprecht
129*99451b44SJordan Rupprecht        self.expect(
130*99451b44SJordan Rupprecht            "frame variable f00_1",
131*99451b44SJordan Rupprecht            substrs=[
132*99451b44SJordan Rupprecht                'a = 280',
133*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
134*99451b44SJordan Rupprecht                'r = 34',
135*99451b44SJordan Rupprecht            ])
136*99451b44SJordan Rupprecht
137*99451b44SJordan Rupprecht        # check that expanding a pointer does the right thing
138*99451b44SJordan Rupprecht        if process.GetByteOrder() == lldb.eByteOrderLittle:
139*99451b44SJordan Rupprecht            fake_a_val = 0x0d000000
140*99451b44SJordan Rupprecht        else:
141*99451b44SJordan Rupprecht            fake_a_val = 0x00000c00
142*99451b44SJordan Rupprecht
143*99451b44SJordan Rupprecht        self.expect(
144*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 f00_ptr",
145*99451b44SJordan Rupprecht            substrs=[
146*99451b44SJordan Rupprecht                'a = 12',
147*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
148*99451b44SJordan Rupprecht                'r = 45',
149*99451b44SJordan Rupprecht            ])
150*99451b44SJordan Rupprecht        self.expect(
151*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 wrapper",
152*99451b44SJordan Rupprecht            substrs=[
153*99451b44SJordan Rupprecht                'a = 12',
154*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
155*99451b44SJordan Rupprecht                'r = 45',
156*99451b44SJordan Rupprecht            ])
157*99451b44SJordan Rupprecht
158*99451b44SJordan Rupprecht        # now add a filter.. it should fail
159*99451b44SJordan Rupprecht        self.expect("type filter add foo --child b --child j", error=True,
160*99451b44SJordan Rupprecht                    substrs=['cannot add'])
161*99451b44SJordan Rupprecht
162*99451b44SJordan Rupprecht        # we get the synth again..
163*99451b44SJordan Rupprecht        self.expect('frame variable f00_1', matching=False,
164*99451b44SJordan Rupprecht                    substrs=['b = 1',
165*99451b44SJordan Rupprecht                             'j = 17'])
166*99451b44SJordan Rupprecht        self.expect(
167*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 f00_ptr",
168*99451b44SJordan Rupprecht            substrs=[
169*99451b44SJordan Rupprecht                'a = 12',
170*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
171*99451b44SJordan Rupprecht                'r = 45',
172*99451b44SJordan Rupprecht            ])
173*99451b44SJordan Rupprecht        self.expect(
174*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 wrapper",
175*99451b44SJordan Rupprecht            substrs=[
176*99451b44SJordan Rupprecht                'a = 12',
177*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
178*99451b44SJordan Rupprecht                'r = 45',
179*99451b44SJordan Rupprecht            ])
180*99451b44SJordan Rupprecht
181*99451b44SJordan Rupprecht        # Test that the custom dereference operator for `wrapfoo` works through
182*99451b44SJordan Rupprecht        # the Python API. The synthetic children provider gets queried at
183*99451b44SJordan Rupprecht        # slightly different times in this case.
184*99451b44SJordan Rupprecht        wrapper_var = thread.GetSelectedFrame().FindVariable('wrapper')
185*99451b44SJordan Rupprecht        foo_var = wrapper_var.Dereference()
186*99451b44SJordan Rupprecht        self.assertEqual(foo_var.GetNumChildren(), 3)
187*99451b44SJordan Rupprecht        self.assertEqual(foo_var.GetChildAtIndex(0).GetName(), 'a')
188*99451b44SJordan Rupprecht        self.assertEqual(foo_var.GetChildAtIndex(1).GetName(), 'fake_a')
189*99451b44SJordan Rupprecht        self.assertEqual(foo_var.GetChildAtIndex(2).GetName(), 'r')
190*99451b44SJordan Rupprecht
191*99451b44SJordan Rupprecht        # now delete the synth and add the filter
192*99451b44SJordan Rupprecht        self.runCmd("type synth delete foo")
193*99451b44SJordan Rupprecht        self.runCmd("type synth delete wrapfoo")
194*99451b44SJordan Rupprecht        self.runCmd("type filter add foo --child b --child j")
195*99451b44SJordan Rupprecht
196*99451b44SJordan Rupprecht        self.expect('frame variable f00_1',
197*99451b44SJordan Rupprecht                    substrs=['b = 2',
198*99451b44SJordan Rupprecht                             'j = 18'])
199*99451b44SJordan Rupprecht        self.expect("frame variable --ptr-depth 1 f00_ptr", matching=False,
200*99451b44SJordan Rupprecht                    substrs=['r = 45',
201*99451b44SJordan Rupprecht                             'fake_a = %d' % fake_a_val,
202*99451b44SJordan Rupprecht                             'a = 12'])
203*99451b44SJordan Rupprecht        self.expect("frame variable --ptr-depth 1 wrapper", matching=False,
204*99451b44SJordan Rupprecht                    substrs=['r = 45',
205*99451b44SJordan Rupprecht                             'fake_a = %d' % fake_a_val,
206*99451b44SJordan Rupprecht                             'a = 12'])
207*99451b44SJordan Rupprecht
208*99451b44SJordan Rupprecht        # now add the synth and it should fail
209*99451b44SJordan Rupprecht        self.expect("type synth add -l fooSynthProvider foo", error=True,
210*99451b44SJordan Rupprecht                    substrs=['cannot add'])
211*99451b44SJordan Rupprecht
212*99451b44SJordan Rupprecht        # check the listing
213*99451b44SJordan Rupprecht        self.expect('type synth list', matching=False,
214*99451b44SJordan Rupprecht                    substrs=['foo',
215*99451b44SJordan Rupprecht                             'Python class fooSynthProvider'])
216*99451b44SJordan Rupprecht        self.expect('type filter list',
217*99451b44SJordan Rupprecht                    substrs=['foo',
218*99451b44SJordan Rupprecht                             '.b',
219*99451b44SJordan Rupprecht                             '.j'])
220*99451b44SJordan Rupprecht
221*99451b44SJordan Rupprecht        # delete the filter, add the synth
222*99451b44SJordan Rupprecht        self.runCmd("type filter delete foo")
223*99451b44SJordan Rupprecht        self.runCmd("type synth add -l fooSynthProvider foo")
224*99451b44SJordan Rupprecht
225*99451b44SJordan Rupprecht        self.expect('frame variable f00_1', matching=False,
226*99451b44SJordan Rupprecht                    substrs=['b = 2',
227*99451b44SJordan Rupprecht                             'j = 18'])
228*99451b44SJordan Rupprecht        self.expect(
229*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 f00_ptr",
230*99451b44SJordan Rupprecht            substrs=[
231*99451b44SJordan Rupprecht                'a = 12',
232*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
233*99451b44SJordan Rupprecht                'r = 45',
234*99451b44SJordan Rupprecht            ])
235*99451b44SJordan Rupprecht        self.expect(
236*99451b44SJordan Rupprecht            "frame variable --ptr-depth 1 wrapper",
237*99451b44SJordan Rupprecht            substrs=[
238*99451b44SJordan Rupprecht                'a = 12',
239*99451b44SJordan Rupprecht                'fake_a = %d' % fake_a_val,
240*99451b44SJordan Rupprecht                'r = 45',
241*99451b44SJordan Rupprecht            ])
242*99451b44SJordan Rupprecht
243*99451b44SJordan Rupprecht        # check the listing
244*99451b44SJordan Rupprecht        self.expect('type synth list',
245*99451b44SJordan Rupprecht                    substrs=['foo',
246*99451b44SJordan Rupprecht                             'Python class fooSynthProvider'])
247*99451b44SJordan Rupprecht        self.expect('type filter list', matching=False,
248*99451b44SJordan Rupprecht                    substrs=['foo',
249*99451b44SJordan Rupprecht                             '.b',
250*99451b44SJordan Rupprecht                             '.j'])
251*99451b44SJordan Rupprecht
252*99451b44SJordan Rupprecht        # delete the synth and check that we get good output
253*99451b44SJordan Rupprecht        self.runCmd("type synth delete foo")
254*99451b44SJordan Rupprecht
255*99451b44SJordan Rupprecht        self.expect("frame variable f00_1",
256*99451b44SJordan Rupprecht                    substrs=['a = 280',
257*99451b44SJordan Rupprecht                             'b = 2',
258*99451b44SJordan Rupprecht                             'j = 18'])
259*99451b44SJordan Rupprecht
260*99451b44SJordan Rupprecht        self.expect("frame variable f00_1", matching=False,
261*99451b44SJordan Rupprecht                    substrs=['fake_a = '])
262*99451b44SJordan Rupprecht
263*99451b44SJordan Rupprecht    def rdar10960550_formatter_commands(self):
264*99451b44SJordan Rupprecht        """Test that synthetic children persist stoppoints."""
265*99451b44SJordan Rupprecht        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
266*99451b44SJordan Rupprecht
267*99451b44SJordan Rupprecht        # The second breakpoint is on a multi-line expression, so the comment
268*99451b44SJordan Rupprecht        # can't be on the right line...
269*99451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
270*99451b44SJordan Rupprecht            self, "main.cpp", self.line2, num_expected_locations=1, loc_exact=False)
271*99451b44SJordan Rupprecht        lldbutil.run_break_set_by_file_and_line(
272*99451b44SJordan Rupprecht            self, "main.cpp", self.line3, num_expected_locations=1, loc_exact=True)
273*99451b44SJordan Rupprecht
274*99451b44SJordan Rupprecht        self.runCmd("run", RUN_SUCCEEDED)
275*99451b44SJordan Rupprecht
276*99451b44SJordan Rupprecht        # The stop reason of the thread should be breakpoint.
277*99451b44SJordan Rupprecht        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
278*99451b44SJordan Rupprecht                    substrs=['stopped',
279*99451b44SJordan Rupprecht                             'stop reason = breakpoint'])
280*99451b44SJordan Rupprecht
281*99451b44SJordan Rupprecht        # This is the function to remove the custom formats in order to have a
282*99451b44SJordan Rupprecht        # clean slate for the next test case.
283*99451b44SJordan Rupprecht        def cleanup():
284*99451b44SJordan Rupprecht            self.runCmd('type format clear', check=False)
285*99451b44SJordan Rupprecht            self.runCmd('type summary clear', check=False)
286*99451b44SJordan Rupprecht            self.runCmd('type filter clear', check=False)
287*99451b44SJordan Rupprecht            self.runCmd('type synth clear', check=False)
288*99451b44SJordan Rupprecht
289*99451b44SJordan Rupprecht        # Execute the cleanup function during test case tear down.
290*99451b44SJordan Rupprecht        self.addTearDownHook(cleanup)
291*99451b44SJordan Rupprecht
292*99451b44SJordan Rupprecht        self.runCmd("command script import ./ftsp.py --allow-reload")
293*99451b44SJordan Rupprecht        self.runCmd("type synth add -l ftsp.ftsp wrapint")
294*99451b44SJordan Rupprecht
295*99451b44SJordan Rupprecht        # we need to check that the VO is properly updated so that the same synthetic children are reused
296*99451b44SJordan Rupprecht        # but their values change correctly across stop-points - in order to do this, self.runCmd("next")
297*99451b44SJordan Rupprecht        # does not work because it forces a wipe of the stack frame - this is why we are using this more contrived
298*99451b44SJordan Rupprecht        # mechanism to achieve our goal of preserving test_cast as a VO
299*99451b44SJordan Rupprecht        test_cast = self.dbg.GetSelectedTarget().GetProcess(
300*99451b44SJordan Rupprecht        ).GetSelectedThread().GetSelectedFrame().FindVariable('test_cast')
301*99451b44SJordan Rupprecht
302*99451b44SJordan Rupprecht        str_cast = str(test_cast)
303*99451b44SJordan Rupprecht
304*99451b44SJordan Rupprecht        if self.TraceOn():
305*99451b44SJordan Rupprecht            print(str_cast)
306*99451b44SJordan Rupprecht
307*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('A') != -1, 'could not find A in output')
308*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('B') != -1, 'could not find B in output')
309*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('C') != -1, 'could not find C in output')
310*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('D') != -1, 'could not find D in output')
311*99451b44SJordan Rupprecht        self.assertTrue(
312*99451b44SJordan Rupprecht            str_cast.find("4 = '\\0'") != -1,
313*99451b44SJordan Rupprecht            'could not find item 4 == 0')
314*99451b44SJordan Rupprecht
315*99451b44SJordan Rupprecht        self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().StepOver()
316*99451b44SJordan Rupprecht
317*99451b44SJordan Rupprecht        str_cast = str(test_cast)
318*99451b44SJordan Rupprecht
319*99451b44SJordan Rupprecht        if self.TraceOn():
320*99451b44SJordan Rupprecht            print(str_cast)
321*99451b44SJordan Rupprecht
322*99451b44SJordan Rupprecht        # we detect that all the values of the child objects have changed - but the counter-generated item
323*99451b44SJordan Rupprecht        # is still fixed at 0 because it is cached - this would fail if update(self): in ftsp returned False
324*99451b44SJordan Rupprecht        # or if synthetic children were not being preserved
325*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('Q') != -1, 'could not find Q in output')
326*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('X') != -1, 'could not find X in output')
327*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('T') != -1, 'could not find T in output')
328*99451b44SJordan Rupprecht        self.assertTrue(str_cast.find('F') != -1, 'could not find F in output')
329*99451b44SJordan Rupprecht        self.assertTrue(
330*99451b44SJordan Rupprecht            str_cast.find("4 = '\\0'") != -1,
331*99451b44SJordan Rupprecht            'could not find item 4 == 0')
332