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