199451b44SJordan Rupprecht""" 299451b44SJordan RupprechtTest lldb data formatter subsystem. 399451b44SJordan Rupprecht""" 499451b44SJordan Rupprecht 599451b44SJordan Rupprechtimport lldb 699451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 799451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 899451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 999451b44SJordan Rupprecht 1099451b44SJordan Rupprecht 1199451b44SJordan Rupprechtclass PythonSynthDataFormatterTestCase(TestBase): 1299451b44SJordan Rupprecht def test_with_run_command(self): 1399451b44SJordan Rupprecht """Test data formatter commands.""" 1499451b44SJordan Rupprecht self.build() 1599451b44SJordan Rupprecht self.data_formatter_commands() 1699451b44SJordan Rupprecht 1799451b44SJordan Rupprecht def test_rdar10960550_with_run_command(self): 1899451b44SJordan Rupprecht """Test data formatter commands.""" 1999451b44SJordan Rupprecht self.build() 2099451b44SJordan Rupprecht self.rdar10960550_formatter_commands() 2199451b44SJordan Rupprecht 2299451b44SJordan Rupprecht def setUp(self): 2399451b44SJordan Rupprecht # Call super's setUp(). 2499451b44SJordan Rupprecht TestBase.setUp(self) 2599451b44SJordan Rupprecht # Find the line number to break at. 262238dcc3SJonas Devlieghere self.line = line_number("main.cpp", "// Set break point at this line.") 272238dcc3SJonas Devlieghere self.line2 = line_number("main.cpp", "// Set cast break point at this line.") 2899451b44SJordan Rupprecht self.line3 = line_number( 292238dcc3SJonas Devlieghere "main.cpp", "// Set second cast break point at this line." 302238dcc3SJonas Devlieghere ) 3199451b44SJordan Rupprecht 3299451b44SJordan Rupprecht def data_formatter_commands(self): 3399451b44SJordan Rupprecht """Test using Python synthetic children provider.""" 3499451b44SJordan Rupprecht 3599451b44SJordan Rupprecht _, process, thread, _ = lldbutil.run_to_line_breakpoint( 362238dcc3SJonas Devlieghere self, lldb.SBFileSpec("main.cpp"), self.line 372238dcc3SJonas Devlieghere ) 3899451b44SJordan Rupprecht 3999451b44SJordan Rupprecht # This is the function to remove the custom formats in order to have a 4099451b44SJordan Rupprecht # clean slate for the next test case. 4199451b44SJordan Rupprecht def cleanup(): 422238dcc3SJonas Devlieghere self.runCmd("type format clear", check=False) 432238dcc3SJonas Devlieghere self.runCmd("type summary clear", check=False) 442238dcc3SJonas Devlieghere self.runCmd("type filter clear", check=False) 452238dcc3SJonas Devlieghere self.runCmd("type synth clear", check=False) 4699451b44SJordan Rupprecht 4799451b44SJordan Rupprecht # Execute the cleanup function during test case tear down. 4899451b44SJordan Rupprecht self.addTearDownHook(cleanup) 4999451b44SJordan Rupprecht 5099451b44SJordan Rupprecht # print the f00_1 variable without a synth 512238dcc3SJonas Devlieghere self.expect("frame variable f00_1", substrs=["a = 1", "b = 2", "r = 34"]) 5299451b44SJordan Rupprecht 5399451b44SJordan Rupprecht # now set up the synth 5499451b44SJordan Rupprecht self.runCmd("script from fooSynthProvider import *") 5599451b44SJordan Rupprecht self.runCmd("type synth add -l fooSynthProvider foo") 5699451b44SJordan Rupprecht self.runCmd("type synth add -l wrapfooSynthProvider wrapfoo") 572238dcc3SJonas Devlieghere self.expect("type synthetic list foo", substrs=["fooSynthProvider"]) 5899451b44SJordan Rupprecht 5999451b44SJordan Rupprecht # note that the value of fake_a depends on target byte order 6099451b44SJordan Rupprecht if process.GetByteOrder() == lldb.eByteOrderLittle: 6199451b44SJordan Rupprecht fake_a_val = 0x02000000 6299451b44SJordan Rupprecht else: 6399451b44SJordan Rupprecht fake_a_val = 0x00000100 6499451b44SJordan Rupprecht 6599451b44SJordan Rupprecht # check that we get the two real vars and the fake_a variables 6699451b44SJordan Rupprecht self.expect( 6799451b44SJordan Rupprecht "frame variable f00_1", 6899451b44SJordan Rupprecht substrs=[ 692238dcc3SJonas Devlieghere "a = 1", 702238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 712238dcc3SJonas Devlieghere "r = 34", 722238dcc3SJonas Devlieghere ], 732238dcc3SJonas Devlieghere ) 7499451b44SJordan Rupprecht 7599451b44SJordan Rupprecht # check that we do not get the extra vars 762238dcc3SJonas Devlieghere self.expect("frame variable f00_1", matching=False, substrs=["b = 2"]) 7799451b44SJordan Rupprecht 7899451b44SJordan Rupprecht # check access to members by name 792238dcc3SJonas Devlieghere self.expect("frame variable f00_1.fake_a", substrs=["%d" % fake_a_val]) 8099451b44SJordan Rupprecht 8199451b44SJordan Rupprecht # check access to members by index 822238dcc3SJonas Devlieghere self.expect("frame variable f00_1[1]", substrs=["%d" % fake_a_val]) 8399451b44SJordan Rupprecht 8499451b44SJordan Rupprecht # put synthetic children in summary in several combinations 852238dcc3SJonas Devlieghere self.runCmd('type summary add --summary-string "fake_a=${svar.fake_a}" foo') 862238dcc3SJonas Devlieghere self.expect("frame variable f00_1", substrs=["fake_a=%d" % fake_a_val]) 872238dcc3SJonas Devlieghere self.runCmd('type summary add --summary-string "fake_a=${svar[1]}" foo') 882238dcc3SJonas Devlieghere self.expect("frame variable f00_1", substrs=["fake_a=%d" % fake_a_val]) 8999451b44SJordan Rupprecht 9099451b44SJordan Rupprecht # clear the summary 9199451b44SJordan Rupprecht self.runCmd("type summary delete foo") 9299451b44SJordan Rupprecht 9399451b44SJordan Rupprecht # check that the caching does not span beyond the stopoint 9499451b44SJordan Rupprecht self.runCmd("n") 9599451b44SJordan Rupprecht 9699451b44SJordan Rupprecht if process.GetByteOrder() == lldb.eByteOrderLittle: 9799451b44SJordan Rupprecht fake_a_val = 0x02000000 9899451b44SJordan Rupprecht else: 9999451b44SJordan Rupprecht fake_a_val = 0x00000200 10099451b44SJordan Rupprecht 10199451b44SJordan Rupprecht self.expect( 10299451b44SJordan Rupprecht "frame variable f00_1", 10399451b44SJordan Rupprecht substrs=[ 1042238dcc3SJonas Devlieghere "a = 2", 1052238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1062238dcc3SJonas Devlieghere "r = 34", 1072238dcc3SJonas Devlieghere ], 1082238dcc3SJonas Devlieghere ) 10999451b44SJordan Rupprecht 11099451b44SJordan Rupprecht # check that altering the object also alters fake_a 11199451b44SJordan Rupprecht self.runCmd("expr f00_1.a = 280") 11299451b44SJordan Rupprecht 11399451b44SJordan Rupprecht if process.GetByteOrder() == lldb.eByteOrderLittle: 11499451b44SJordan Rupprecht fake_a_val = 0x02000001 11599451b44SJordan Rupprecht else: 11699451b44SJordan Rupprecht fake_a_val = 0x00011800 11799451b44SJordan Rupprecht 11899451b44SJordan Rupprecht self.expect( 11999451b44SJordan Rupprecht "frame variable f00_1", 12099451b44SJordan Rupprecht substrs=[ 1212238dcc3SJonas Devlieghere "a = 280", 1222238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1232238dcc3SJonas Devlieghere "r = 34", 1242238dcc3SJonas Devlieghere ], 1252238dcc3SJonas Devlieghere ) 12699451b44SJordan Rupprecht 12799451b44SJordan Rupprecht # check that expanding a pointer does the right thing 12899451b44SJordan Rupprecht if process.GetByteOrder() == lldb.eByteOrderLittle: 1292238dcc3SJonas Devlieghere fake_a_val = 0x0D000000 13099451b44SJordan Rupprecht else: 1312238dcc3SJonas Devlieghere fake_a_val = 0x00000C00 13299451b44SJordan Rupprecht 13399451b44SJordan Rupprecht self.expect( 13499451b44SJordan Rupprecht "frame variable --ptr-depth 1 f00_ptr", 13599451b44SJordan Rupprecht substrs=[ 1362238dcc3SJonas Devlieghere "a = 12", 1372238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1382238dcc3SJonas Devlieghere "r = 45", 1392238dcc3SJonas Devlieghere ], 1402238dcc3SJonas Devlieghere ) 14199451b44SJordan Rupprecht self.expect( 14299451b44SJordan Rupprecht "frame variable --ptr-depth 1 wrapper", 14399451b44SJordan Rupprecht substrs=[ 1442238dcc3SJonas Devlieghere "a = 12", 1452238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1462238dcc3SJonas Devlieghere "r = 45", 1472238dcc3SJonas Devlieghere ], 1482238dcc3SJonas Devlieghere ) 14999451b44SJordan Rupprecht 15099451b44SJordan Rupprecht # now add a filter.. it should fail 1512238dcc3SJonas Devlieghere self.expect( 1522238dcc3SJonas Devlieghere "type filter add foo --child b --child j", 1532238dcc3SJonas Devlieghere error=True, 1542238dcc3SJonas Devlieghere substrs=["cannot add"], 1552238dcc3SJonas Devlieghere ) 15699451b44SJordan Rupprecht 15799451b44SJordan Rupprecht # we get the synth again.. 1582238dcc3SJonas Devlieghere self.expect("frame variable f00_1", matching=False, substrs=["b = 1", "j = 17"]) 15999451b44SJordan Rupprecht self.expect( 16099451b44SJordan Rupprecht "frame variable --ptr-depth 1 f00_ptr", 16199451b44SJordan Rupprecht substrs=[ 1622238dcc3SJonas Devlieghere "a = 12", 1632238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1642238dcc3SJonas Devlieghere "r = 45", 1652238dcc3SJonas Devlieghere ], 1662238dcc3SJonas Devlieghere ) 16799451b44SJordan Rupprecht self.expect( 16899451b44SJordan Rupprecht "frame variable --ptr-depth 1 wrapper", 16999451b44SJordan Rupprecht substrs=[ 1702238dcc3SJonas Devlieghere "a = 12", 1712238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 1722238dcc3SJonas Devlieghere "r = 45", 1732238dcc3SJonas Devlieghere ], 1742238dcc3SJonas Devlieghere ) 17599451b44SJordan Rupprecht 17699451b44SJordan Rupprecht # Test that the custom dereference operator for `wrapfoo` works through 17799451b44SJordan Rupprecht # the Python API. The synthetic children provider gets queried at 17899451b44SJordan Rupprecht # slightly different times in this case. 1792238dcc3SJonas Devlieghere wrapper_var = thread.GetSelectedFrame().FindVariable("wrapper") 18099451b44SJordan Rupprecht foo_var = wrapper_var.Dereference() 18199451b44SJordan Rupprecht self.assertEqual(foo_var.GetNumChildren(), 3) 1822238dcc3SJonas Devlieghere self.assertEqual(foo_var.GetChildAtIndex(0).GetName(), "a") 1832238dcc3SJonas Devlieghere self.assertEqual(foo_var.GetChildAtIndex(1).GetName(), "fake_a") 1842238dcc3SJonas Devlieghere self.assertEqual(foo_var.GetChildAtIndex(2).GetName(), "r") 18599451b44SJordan Rupprecht 18699451b44SJordan Rupprecht # now delete the synth and add the filter 18799451b44SJordan Rupprecht self.runCmd("type synth delete foo") 18899451b44SJordan Rupprecht self.runCmd("type synth delete wrapfoo") 18999451b44SJordan Rupprecht self.runCmd("type filter add foo --child b --child j") 19099451b44SJordan Rupprecht 1912238dcc3SJonas Devlieghere self.expect("frame variable f00_1", substrs=["b = 2", "j = 18"]) 1922238dcc3SJonas Devlieghere self.expect( 1932238dcc3SJonas Devlieghere "frame variable --ptr-depth 1 f00_ptr", 1942238dcc3SJonas Devlieghere matching=False, 1952238dcc3SJonas Devlieghere substrs=["r = 45", "fake_a = %d" % fake_a_val, "a = 12"], 1962238dcc3SJonas Devlieghere ) 1972238dcc3SJonas Devlieghere self.expect( 1982238dcc3SJonas Devlieghere "frame variable --ptr-depth 1 wrapper", 1992238dcc3SJonas Devlieghere matching=False, 2002238dcc3SJonas Devlieghere substrs=["r = 45", "fake_a = %d" % fake_a_val, "a = 12"], 2012238dcc3SJonas Devlieghere ) 20299451b44SJordan Rupprecht 20399451b44SJordan Rupprecht # now add the synth and it should fail 2042238dcc3SJonas Devlieghere self.expect( 2052238dcc3SJonas Devlieghere "type synth add -l fooSynthProvider foo", error=True, substrs=["cannot add"] 2062238dcc3SJonas Devlieghere ) 20799451b44SJordan Rupprecht 20899451b44SJordan Rupprecht # check the listing 2092238dcc3SJonas Devlieghere self.expect( 2102238dcc3SJonas Devlieghere "type synth list", 2112238dcc3SJonas Devlieghere matching=False, 2122238dcc3SJonas Devlieghere substrs=["foo", "Python class fooSynthProvider"], 2132238dcc3SJonas Devlieghere ) 2142238dcc3SJonas Devlieghere self.expect("type filter list", substrs=["foo", ".b", ".j"]) 21599451b44SJordan Rupprecht 21699451b44SJordan Rupprecht # delete the filter, add the synth 21799451b44SJordan Rupprecht self.runCmd("type filter delete foo") 21899451b44SJordan Rupprecht self.runCmd("type synth add -l fooSynthProvider foo") 21999451b44SJordan Rupprecht 2202238dcc3SJonas Devlieghere self.expect("frame variable f00_1", matching=False, substrs=["b = 2", "j = 18"]) 22199451b44SJordan Rupprecht self.expect( 22299451b44SJordan Rupprecht "frame variable --ptr-depth 1 f00_ptr", 22399451b44SJordan Rupprecht substrs=[ 2242238dcc3SJonas Devlieghere "a = 12", 2252238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 2262238dcc3SJonas Devlieghere "r = 45", 2272238dcc3SJonas Devlieghere ], 2282238dcc3SJonas Devlieghere ) 22999451b44SJordan Rupprecht self.expect( 23099451b44SJordan Rupprecht "frame variable --ptr-depth 1 wrapper", 23199451b44SJordan Rupprecht substrs=[ 2322238dcc3SJonas Devlieghere "a = 12", 2332238dcc3SJonas Devlieghere "fake_a = %d" % fake_a_val, 2342238dcc3SJonas Devlieghere "r = 45", 2352238dcc3SJonas Devlieghere ], 2362238dcc3SJonas Devlieghere ) 23799451b44SJordan Rupprecht 23899451b44SJordan Rupprecht # check the listing 2392238dcc3SJonas Devlieghere self.expect("type synth list", substrs=["foo", "Python class fooSynthProvider"]) 2402238dcc3SJonas Devlieghere self.expect("type filter list", matching=False, substrs=["foo", ".b", ".j"]) 24199451b44SJordan Rupprecht 24299451b44SJordan Rupprecht # delete the synth and check that we get good output 24399451b44SJordan Rupprecht self.runCmd("type synth delete foo") 24499451b44SJordan Rupprecht 2452238dcc3SJonas Devlieghere self.expect("frame variable f00_1", substrs=["a = 280", "b = 2", "j = 18"]) 24699451b44SJordan Rupprecht 2472238dcc3SJonas Devlieghere self.expect("frame variable f00_1", matching=False, substrs=["fake_a = "]) 24899451b44SJordan Rupprecht 24969c661a6SJorge Gorbe Moya # check that we don't feed a regex into another regex when checking for 25069c661a6SJorge Gorbe Moya # existing conflicting synth/filters. The two following expressions 25169c661a6SJorge Gorbe Moya # accept different types: one will accept types that look like an array 25269c661a6SJorge Gorbe Moya # of MyType, the other will accept types that contain "MyType1" or 25369c661a6SJorge Gorbe Moya # "MyType2". But the second regex looks like an array of MyType, so 25469c661a6SJorge Gorbe Moya # lldb used to incorrectly reject it. 25569c661a6SJorge Gorbe Moya self.runCmd(r'type synth add -l fooSynthProvider -x "^MyType\[[0-9]+]$"') 25669c661a6SJorge Gorbe Moya self.runCmd(r'type filter add --child a -x "MyType[12]"') 25769c661a6SJorge Gorbe Moya 25869c661a6SJorge Gorbe Moya # Same, but adding the filter first to verify the check when doing 25969c661a6SJorge Gorbe Moya # `type synth add`. We need to delete the synth from the previous test 26069c661a6SJorge Gorbe Moya # first. 26169c661a6SJorge Gorbe Moya self.runCmd(r'type synth delete "^MyType\[[0-9]+]$"') 26269c661a6SJorge Gorbe Moya self.runCmd(r'type filter add --child a -x "^MyType\[[0-9]+]$"') 26369c661a6SJorge Gorbe Moya self.runCmd(r'type synth add -l fooSynthProvider -x "MyType[12]"') 26469c661a6SJorge Gorbe Moya 26599451b44SJordan Rupprecht def rdar10960550_formatter_commands(self): 26699451b44SJordan Rupprecht """Test that synthetic children persist stoppoints.""" 26799451b44SJordan Rupprecht self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) 26899451b44SJordan Rupprecht 26999451b44SJordan Rupprecht # The second breakpoint is on a multi-line expression, so the comment 27099451b44SJordan Rupprecht # can't be on the right line... 27199451b44SJordan Rupprecht lldbutil.run_break_set_by_file_and_line( 2722238dcc3SJonas Devlieghere self, "main.cpp", self.line2, num_expected_locations=1, loc_exact=False 2732238dcc3SJonas Devlieghere ) 27499451b44SJordan Rupprecht lldbutil.run_break_set_by_file_and_line( 2752238dcc3SJonas Devlieghere self, "main.cpp", self.line3, num_expected_locations=1, loc_exact=True 2762238dcc3SJonas Devlieghere ) 27799451b44SJordan Rupprecht 27899451b44SJordan Rupprecht self.runCmd("run", RUN_SUCCEEDED) 27999451b44SJordan Rupprecht 28099451b44SJordan Rupprecht # The stop reason of the thread should be breakpoint. 2812238dcc3SJonas Devlieghere self.expect( 2822238dcc3SJonas Devlieghere "thread list", 2832238dcc3SJonas Devlieghere STOPPED_DUE_TO_BREAKPOINT, 2842238dcc3SJonas Devlieghere substrs=["stopped", "stop reason = breakpoint"], 2852238dcc3SJonas Devlieghere ) 28699451b44SJordan Rupprecht 28799451b44SJordan Rupprecht # This is the function to remove the custom formats in order to have a 28899451b44SJordan Rupprecht # clean slate for the next test case. 28999451b44SJordan Rupprecht def cleanup(): 2902238dcc3SJonas Devlieghere self.runCmd("type format clear", check=False) 2912238dcc3SJonas Devlieghere self.runCmd("type summary clear", check=False) 2922238dcc3SJonas Devlieghere self.runCmd("type filter clear", check=False) 2932238dcc3SJonas Devlieghere self.runCmd("type synth clear", check=False) 29499451b44SJordan Rupprecht 29599451b44SJordan Rupprecht # Execute the cleanup function during test case tear down. 29699451b44SJordan Rupprecht self.addTearDownHook(cleanup) 29799451b44SJordan Rupprecht 29899451b44SJordan Rupprecht self.runCmd("command script import ./ftsp.py --allow-reload") 29999451b44SJordan Rupprecht self.runCmd("type synth add -l ftsp.ftsp wrapint") 30099451b44SJordan Rupprecht 30199451b44SJordan Rupprecht # we need to check that the VO is properly updated so that the same synthetic children are reused 30299451b44SJordan Rupprecht # but their values change correctly across stop-points - in order to do this, self.runCmd("next") 30399451b44SJordan Rupprecht # does not work because it forces a wipe of the stack frame - this is why we are using this more contrived 30499451b44SJordan Rupprecht # mechanism to achieve our goal of preserving test_cast as a VO 3052238dcc3SJonas Devlieghere test_cast = ( 3062238dcc3SJonas Devlieghere self.dbg.GetSelectedTarget() 3072238dcc3SJonas Devlieghere .GetProcess() 3082238dcc3SJonas Devlieghere .GetSelectedThread() 3092238dcc3SJonas Devlieghere .GetSelectedFrame() 3102238dcc3SJonas Devlieghere .FindVariable("test_cast") 3112238dcc3SJonas Devlieghere ) 31299451b44SJordan Rupprecht 31399451b44SJordan Rupprecht str_cast = str(test_cast) 31499451b44SJordan Rupprecht 31599451b44SJordan Rupprecht if self.TraceOn(): 31699451b44SJordan Rupprecht print(str_cast) 31799451b44SJordan Rupprecht 318*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("A"), -1, "could not find A in output") 319*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("B"), -1, "could not find B in output") 320*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("C"), -1, "could not find C in output") 321*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("D"), -1, "could not find D in output") 322*9c246882SJordan Rupprecht self.assertNotEqual( 323*9c246882SJordan Rupprecht str_cast.find("4 = '\\0'"), -1, "could not find item 4 == 0" 324*9c246882SJordan Rupprecht ) 32599451b44SJordan Rupprecht 32699451b44SJordan Rupprecht self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().StepOver() 32799451b44SJordan Rupprecht 32899451b44SJordan Rupprecht str_cast = str(test_cast) 32999451b44SJordan Rupprecht 33099451b44SJordan Rupprecht if self.TraceOn(): 33199451b44SJordan Rupprecht print(str_cast) 33299451b44SJordan Rupprecht 33399451b44SJordan Rupprecht # we detect that all the values of the child objects have changed - but the counter-generated item 33499451b44SJordan Rupprecht # is still fixed at 0 because it is cached - this would fail if update(self): in ftsp returned False 33599451b44SJordan Rupprecht # or if synthetic children were not being preserved 336*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("Q"), -1, "could not find Q in output") 337*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("X"), -1, "could not find X in output") 338*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("T"), -1, "could not find T in output") 339*9c246882SJordan Rupprecht self.assertNotEqual(str_cast.find("F"), -1, "could not find F in output") 340*9c246882SJordan Rupprecht self.assertNotEqual( 341*9c246882SJordan Rupprecht str_cast.find("4 = '\\0'"), -1, "could not find item 4 == 0" 342*9c246882SJordan Rupprecht ) 343