1"""Test Python APIs for working with formatters""" 2 3import lldb 4from lldbsuite.test.decorators import * 5from lldbsuite.test.lldbtest import * 6from lldbsuite.test import lldbutil 7 8 9class SBFormattersAPITestCase(TestBase): 10 NO_DEBUG_INFO_TESTCASE = True 11 12 def setUp(self): 13 # Call super's setUp(). 14 TestBase.setUp(self) 15 self.line = line_number("main.cpp", "// Set break point at this line.") 16 17 def test_formatters_api(self): 18 """Test Python APIs for working with formatters""" 19 self.build() 20 self.setTearDownCleanup() 21 22 """Test Python APIs for working with formatters""" 23 self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) 24 25 lldbutil.run_break_set_by_file_and_line( 26 self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True 27 ) 28 29 self.runCmd("run", RUN_SUCCEEDED) 30 31 # The stop reason of the thread should be breakpoint. 32 self.expect( 33 "thread list", 34 STOPPED_DUE_TO_BREAKPOINT, 35 substrs=["stopped", "stop reason = breakpoint"], 36 ) 37 38 # This is the function to remove the custom formats in order to have a 39 # clean slate for the next test case. 40 def cleanup(): 41 self.runCmd("type format clear", check=False) 42 self.runCmd("type summary clear", check=False) 43 self.runCmd("type filter clear", check=False) 44 self.runCmd("type synthetic clear", check=False) 45 self.runCmd("type category delete foobar", check=False) 46 self.runCmd("type category delete JASSynth", check=False) 47 self.runCmd("type category delete newbar", check=False) 48 49 # Execute the cleanup function during test case tear down. 50 self.addTearDownHook(cleanup) 51 52 format = lldb.SBTypeFormat(lldb.eFormatHex) 53 category = self.dbg.GetDefaultCategory() 54 category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format) 55 56 self.expect("frame variable foo.A", substrs=["0x00000001"]) 57 self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"]) 58 59 category.AddTypeFormat(lldb.SBTypeNameSpecifier("long"), format) 60 self.expect("frame variable foo.A", substrs=["0x00000001"]) 61 self.expect("frame variable foo.E", substrs=["b8cca70a"]) 62 63 format.SetFormat(lldb.eFormatOctal) 64 category.AddTypeFormat(lldb.SBTypeNameSpecifier("int"), format) 65 self.expect("frame variable foo.A", substrs=[" 01"]) 66 self.expect("frame variable foo.E", substrs=["b8cca70a"]) 67 68 category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("int")) 69 category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("long")) 70 self.expect("frame variable foo.A", matching=False, substrs=[" 01"]) 71 self.expect("frame variable foo.E", matching=False, substrs=["b8cca70a"]) 72 73 summary = lldb.SBTypeSummary.CreateWithSummaryString( 74 "the hello world you'll never see" 75 ) 76 summary.SetSummaryString("hello world") 77 new_category = self.dbg.GetCategory("foobar") 78 self.assertFalse( 79 new_category.IsValid(), "getting a non-existing category worked" 80 ) 81 new_category = self.dbg.CreateCategory("foobar") 82 new_category.SetEnabled(True) 83 new_category.AddTypeSummary( 84 lldb.SBTypeNameSpecifier( 85 "^.*t$", 86 True, # is_regexp 87 ), 88 summary, 89 ) 90 91 self.expect("frame variable foo.A", substrs=["hello world"]) 92 self.expect("frame variable foo.E", matching=False, substrs=["hello world"]) 93 self.expect("frame variable foo.B", substrs=["hello world"]) 94 self.expect("frame variable foo.F", substrs=["hello world"]) 95 new_category.SetEnabled(False) 96 self.expect("frame variable foo.A", matching=False, substrs=["hello world"]) 97 self.expect("frame variable foo.E", matching=False, substrs=["hello world"]) 98 self.expect("frame variable foo.B", matching=False, substrs=["hello world"]) 99 self.expect("frame variable foo.F", matching=False, substrs=["hello world"]) 100 self.dbg.DeleteCategory(new_category.GetName()) 101 self.expect("frame variable foo.A", matching=False, substrs=["hello world"]) 102 self.expect("frame variable foo.E", matching=False, substrs=["hello world"]) 103 self.expect("frame variable foo.B", matching=False, substrs=["hello world"]) 104 self.expect("frame variable foo.F", matching=False, substrs=["hello world"]) 105 106 filter = lldb.SBTypeFilter(0) 107 filter.AppendExpressionPath("A") 108 filter.AppendExpressionPath("D") 109 self.assertEqual( 110 filter.GetNumberOfExpressionPaths(), 111 2, 112 "filter with two items does not have two items", 113 ) 114 115 category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter) 116 self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"]) 117 self.expect( 118 "frame variable foo", 119 matching=False, 120 substrs=["B = ", "C = ", "E = ", "F = "], 121 ) 122 123 category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", True)) 124 self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"]) 125 self.expect( 126 "frame variable foo", 127 matching=False, 128 substrs=["B = ", "C = ", "E = ", "F = "], 129 ) 130 131 category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct", False)) 132 self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"]) 133 self.expect( 134 "frame variable foo", 135 matching=True, 136 substrs=["B = ", "C = ", "E = ", "F = "], 137 ) 138 139 self.runCmd("command script import --allow-reload ./synth.py") 140 141 self.expect("frame variable foo", matching=False, substrs=["X = 1"]) 142 143 self.dbg.GetCategory("JASSynth").SetEnabled(True) 144 self.expect("frame variable foo", matching=True, substrs=["X = 1"]) 145 146 self.dbg.GetCategory("CCCSynth2").SetEnabled(True) 147 self.expect( 148 "frame variable ccc", 149 matching=True, 150 substrs=[ 151 "CCC object with leading synthetic value (int) b = 222", 152 "a = 111", 153 "b = 222", 154 "c = 333", 155 ], 156 ) 157 self.dbg.GetCategory("CCCSynth2").SetEnabled(False) 158 159 self.dbg.GetCategory("CCCSynth").SetEnabled(True) 160 self.expect( 161 "frame variable ccc", 162 matching=True, 163 substrs=[ 164 "CCC object with leading value (int) a = 111", 165 "a = 111", 166 "b = 222", 167 "c = 333", 168 ], 169 ) 170 171 self.dbg.GetCategory("BarIntSynth").SetEnabled(True) 172 self.expect( 173 "frame variable bar_int", 174 matching=True, 175 substrs=[ 176 "(int) bar_int = 20 bar_int synthetic: No value", 177 ], 178 ) 179 180 foo_var = ( 181 self.dbg.GetSelectedTarget() 182 .GetProcess() 183 .GetSelectedThread() 184 .GetSelectedFrame() 185 .FindVariable("foo") 186 ) 187 self.assertTrue(foo_var.IsValid(), "could not find foo") 188 self.assertTrue( 189 foo_var.GetDeclaration().IsValid(), "foo declaration is invalid" 190 ) 191 192 self.assertEqual( 193 foo_var.GetNumChildren(), 194 2, 195 "synthetic value has wrong number of child items (synth)", 196 ) 197 self.assertEqual( 198 foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(), 199 1, 200 "foo_synth.X has wrong value (synth)", 201 ) 202 self.assertFalse( 203 foo_var.GetChildMemberWithName("B").IsValid(), 204 "foo_synth.B is valid but should not (synth)", 205 ) 206 207 self.dbg.GetCategory("JASSynth").SetEnabled(False) 208 foo_var = ( 209 self.dbg.GetSelectedTarget() 210 .GetProcess() 211 .GetSelectedThread() 212 .GetSelectedFrame() 213 .FindVariable("foo") 214 ) 215 self.assertTrue(foo_var.IsValid(), "could not find foo") 216 217 self.assertNotEqual(foo_var.GetNumChildren(), 2, "still seeing synthetic value") 218 219 filter = lldb.SBTypeFilter(0) 220 filter.AppendExpressionPath("A") 221 filter.AppendExpressionPath("D") 222 category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter) 223 self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"]) 224 225 foo_var = ( 226 self.dbg.GetSelectedTarget() 227 .GetProcess() 228 .GetSelectedThread() 229 .GetSelectedFrame() 230 .FindVariable("foo") 231 ) 232 self.assertTrue(foo_var.IsValid(), "could not find foo") 233 234 self.assertEqual( 235 foo_var.GetNumChildren(), 236 2, 237 "synthetic value has wrong number of child items (filter)", 238 ) 239 self.assertEqual( 240 foo_var.GetChildMemberWithName("X").GetValueAsUnsigned(), 241 0, 242 "foo_synth.X has wrong value (filter)", 243 ) 244 self.assertEqual( 245 foo_var.GetChildMemberWithName("A").GetValueAsUnsigned(), 246 1, 247 "foo_synth.A has wrong value (filter)", 248 ) 249 250 self.assertTrue( 251 filter.ReplaceExpressionPathAtIndex(0, "C"), 252 "failed to replace an expression path in filter", 253 ) 254 self.expect("frame variable foo", substrs=["A = 1", "D = 6.28"]) 255 category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter) 256 self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"]) 257 category.AddTypeFilter(lldb.SBTypeNameSpecifier("FooType"), filter) 258 filter.ReplaceExpressionPathAtIndex(1, "F") 259 self.expect("frame variable foo", substrs=["C = 'e'", "D = 6.28"]) 260 category.AddTypeFilter(lldb.SBTypeNameSpecifier("JustAStruct"), filter) 261 self.expect("frame variable foo", substrs=["C = 'e'", "F = 0"]) 262 self.expect("frame variable bar", substrs=["C = 'e'", "D = 6.28"]) 263 264 foo_var = ( 265 self.dbg.GetSelectedTarget() 266 .GetProcess() 267 .GetSelectedThread() 268 .GetSelectedFrame() 269 .FindVariable("foo") 270 ) 271 self.assertTrue(foo_var.IsValid(), "could not find foo") 272 self.assertEqual( 273 foo_var.GetChildMemberWithName("C").GetValueAsUnsigned(), 274 ord("e"), 275 "foo_synth.C has wrong value (filter)", 276 ) 277 278 chosen = self.dbg.GetFilterForType(lldb.SBTypeNameSpecifier("JustAStruct")) 279 self.assertEqual(chosen.count, 2, "wrong filter found for JustAStruct") 280 self.assertEqual( 281 chosen.GetExpressionPathAtIndex(0), 282 "C", 283 "wrong item at index 0 for JustAStruct", 284 ) 285 self.assertEqual( 286 chosen.GetExpressionPathAtIndex(1), 287 "F", 288 "wrong item at index 1 for JustAStruct", 289 ) 290 291 self.assertFalse( 292 category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("NoSuchType")), 293 "deleting a non-existing filter worked", 294 ) 295 self.assertFalse( 296 category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("NoSuchType")), 297 "deleting a non-existing summary worked", 298 ) 299 self.assertFalse( 300 category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("NoSuchType")), 301 "deleting a non-existing format worked", 302 ) 303 self.assertFalse( 304 category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("NoSuchType")), 305 "deleting a non-existing synthetic worked", 306 ) 307 308 self.assertFalse( 309 category.DeleteTypeFilter(lldb.SBTypeNameSpecifier("")), 310 "deleting a filter for '' worked", 311 ) 312 self.assertFalse( 313 category.DeleteTypeSummary(lldb.SBTypeNameSpecifier("")), 314 "deleting a summary for '' worked", 315 ) 316 self.assertFalse( 317 category.DeleteTypeFormat(lldb.SBTypeNameSpecifier("")), 318 "deleting a format for '' worked", 319 ) 320 self.assertFalse( 321 category.DeleteTypeSynthetic(lldb.SBTypeNameSpecifier("")), 322 "deleting a synthetic for '' worked", 323 ) 324 325 try: 326 self.assertFalse( 327 category.AddTypeSummary(lldb.SBTypeNameSpecifier("NoneSuchType"), None), 328 "adding a summary valued None worked", 329 ) 330 except: 331 pass 332 else: 333 self.assertFalse(True, "adding a summary valued None worked") 334 335 try: 336 self.assertFalse( 337 category.AddTypeFilter(lldb.SBTypeNameSpecifier("NoneSuchType"), None), 338 "adding a filter valued None worked", 339 ) 340 except: 341 pass 342 else: 343 self.assertFalse(True, "adding a filter valued None worked") 344 345 try: 346 self.assertFalse( 347 category.AddTypeSynthetic( 348 lldb.SBTypeNameSpecifier("NoneSuchType"), None 349 ), 350 "adding a synthetic valued None worked", 351 ) 352 except: 353 pass 354 else: 355 self.assertFalse(True, "adding a synthetic valued None worked") 356 357 try: 358 self.assertFalse( 359 category.AddTypeFormat(lldb.SBTypeNameSpecifier("NoneSuchType"), None), 360 "adding a format valued None worked", 361 ) 362 except: 363 pass 364 else: 365 self.assertFalse(True, "adding a format valued None worked") 366 367 self.assertFalse( 368 category.AddTypeSummary( 369 lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSummary() 370 ), 371 "adding a summary without value worked", 372 ) 373 self.assertFalse( 374 category.AddTypeFilter( 375 lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFilter() 376 ), 377 "adding a filter without value worked", 378 ) 379 self.assertFalse( 380 category.AddTypeSynthetic( 381 lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeSynthetic() 382 ), 383 "adding a synthetic without value worked", 384 ) 385 self.assertFalse( 386 category.AddTypeFormat( 387 lldb.SBTypeNameSpecifier("EmptySuchType"), lldb.SBTypeFormat() 388 ), 389 "adding a format without value worked", 390 ) 391 392 self.assertFalse( 393 category.AddTypeSummary( 394 lldb.SBTypeNameSpecifier(""), 395 lldb.SBTypeSummary.CreateWithSummaryString(""), 396 ), 397 "adding a summary for an invalid type worked", 398 ) 399 self.assertFalse( 400 category.AddTypeFilter(lldb.SBTypeNameSpecifier(""), lldb.SBTypeFilter(0)), 401 "adding a filter for an invalid type worked", 402 ) 403 self.assertFalse( 404 category.AddTypeSynthetic( 405 lldb.SBTypeNameSpecifier(""), 406 lldb.SBTypeSynthetic.CreateWithClassName(""), 407 ), 408 "adding a synthetic for an invalid type worked", 409 ) 410 self.assertFalse( 411 category.AddTypeFormat( 412 lldb.SBTypeNameSpecifier(""), lldb.SBTypeFormat(lldb.eFormatHex) 413 ), 414 "adding a format for an invalid type worked", 415 ) 416 417 new_category = self.dbg.CreateCategory("newbar") 418 new_category.AddTypeSummary( 419 lldb.SBTypeNameSpecifier("JustAStruct"), 420 lldb.SBTypeSummary.CreateWithScriptCode("return 'hello scripted world';"), 421 ) 422 self.expect( 423 "frame variable foo", matching=False, substrs=["hello scripted world"] 424 ) 425 new_category.SetEnabled(True) 426 self.expect( 427 "frame variable foo", matching=True, substrs=["hello scripted world"] 428 ) 429 430 self.expect( 431 "frame variable foo_ptr", matching=True, substrs=["hello scripted world"] 432 ) 433 new_category.AddTypeSummary( 434 lldb.SBTypeNameSpecifier("JustAStruct"), 435 lldb.SBTypeSummary.CreateWithScriptCode( 436 "return 'hello scripted world';", lldb.eTypeOptionSkipPointers 437 ), 438 ) 439 self.expect( 440 "frame variable foo", matching=True, substrs=["hello scripted world"] 441 ) 442 443 frame = ( 444 self.dbg.GetSelectedTarget() 445 .GetProcess() 446 .GetSelectedThread() 447 .GetSelectedFrame() 448 ) 449 foo_ptr = frame.FindVariable("foo_ptr") 450 summary = foo_ptr.GetTypeSummary() 451 452 self.assertFalse( 453 summary.IsValid(), "summary found for foo* when none was planned" 454 ) 455 456 self.expect( 457 "frame variable foo_ptr", matching=False, substrs=["hello scripted world"] 458 ) 459 460 new_category.AddTypeSummary( 461 lldb.SBTypeNameSpecifier("JustAStruct"), 462 lldb.SBTypeSummary.CreateWithSummaryString( 463 "hello static world", lldb.eTypeOptionNone 464 ), 465 ) 466 467 summary = foo_ptr.GetTypeSummary() 468 469 self.assertTrue( 470 summary.IsValid(), "no summary found for foo* when one was in place" 471 ) 472 self.assertEqual( 473 summary.GetData(), "hello static world", "wrong summary found for foo*" 474 ) 475 476 self.expect("frame variable e1", substrs=["I am an empty Empty1 {}"]) 477 self.expect("frame variable e2", substrs=["I am an empty Empty2"]) 478 self.expect( 479 "frame variable e2", substrs=["I am an empty Empty2 {}"], matching=False 480 ) 481 482 self.assertIsNotNone( 483 self.dbg.GetCategory(lldb.eLanguageTypeObjC), "ObjC category is None" 484 ) 485 486 def test_force_synth_off(self): 487 """Test that one can have the public API return non-synthetic SBValues if desired""" 488 self.build(dictionary={"EXE": "no_synth"}) 489 self.setTearDownCleanup() 490 491 self.runCmd("file " + self.getBuildArtifact("no_synth"), CURRENT_EXECUTABLE_SET) 492 493 lldbutil.run_break_set_by_file_and_line( 494 self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True 495 ) 496 497 self.runCmd("run", RUN_SUCCEEDED) 498 499 # The stop reason of the thread should be breakpoint. 500 self.expect( 501 "thread list", 502 STOPPED_DUE_TO_BREAKPOINT, 503 substrs=["stopped", "stop reason = breakpoint"], 504 ) 505 506 # This is the function to remove the custom formats in order to have a 507 # clean slate for the next test case. 508 def cleanup(): 509 self.runCmd("type format clear", check=False) 510 self.runCmd("type summary clear", check=False) 511 self.runCmd("type filter clear", check=False) 512 self.runCmd("type synthetic clear", check=False) 513 self.runCmd("type category delete foobar", check=False) 514 self.runCmd("type category delete JASSynth", check=False) 515 self.runCmd("type category delete newbar", check=False) 516 self.runCmd("settings set target.enable-synthetic-value true") 517 518 # Execute the cleanup function during test case tear down. 519 self.addTearDownHook(cleanup) 520 521 frame = ( 522 self.dbg.GetSelectedTarget() 523 .GetProcess() 524 .GetSelectedThread() 525 .GetSelectedFrame() 526 ) 527 int_vector = frame.FindVariable("int_vector") 528 if self.TraceOn(): 529 print(int_vector) 530 self.assertEqual(int_vector.GetNumChildren(), 0, "synthetic vector is empty") 531 532 self.runCmd("settings set target.enable-synthetic-value false") 533 frame = ( 534 self.dbg.GetSelectedTarget() 535 .GetProcess() 536 .GetSelectedThread() 537 .GetSelectedFrame() 538 ) 539 int_vector = frame.FindVariable("int_vector") 540 if self.TraceOn(): 541 print(int_vector) 542 self.assertNotEqual( 543 int_vector.GetNumChildren(), 0, '"physical" vector is not empty' 544 ) 545 546 self.runCmd("settings set target.enable-synthetic-value true") 547 frame = ( 548 self.dbg.GetSelectedTarget() 549 .GetProcess() 550 .GetSelectedThread() 551 .GetSelectedFrame() 552 ) 553 int_vector = frame.FindVariable("int_vector") 554 if self.TraceOn(): 555 print(int_vector) 556 self.assertEqual( 557 int_vector.GetNumChildren(), 0, "synthetic vector is still empty" 558 ) 559