1# encoding: utf-8 2""" 3Test lldb's frame recognizers. 4""" 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11import recognizer 12 13 14class FrameRecognizerTestCase(TestBase): 15 NO_DEBUG_INFO_TESTCASE = True 16 17 def test_frame_recognizer_1(self): 18 self.build() 19 exe = self.getBuildArtifact("a.out") 20 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 21 self, "foo", exe_name=exe 22 ) 23 frame = thread.selected_frame 24 25 # Clear internal & plugins recognizers that get initialized at launch 26 self.runCmd("frame recognizer clear") 27 28 self.runCmd( 29 "command script import " 30 + os.path.join(self.getSourceDir(), "recognizer.py") 31 ) 32 33 self.expect("frame recognizer list", substrs=["no matching results found."]) 34 35 self.runCmd( 36 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo" 37 ) 38 39 self.expect( 40 "frame recognizer list", 41 substrs=[ 42 "0: recognizer.MyFrameRecognizer, module a.out, demangled symbol foo" 43 ], 44 ) 45 46 self.runCmd( 47 "frame recognizer add -l recognizer.MyOtherFrameRecognizer -s a.out -n bar -x" 48 ) 49 50 self.expect( 51 "frame recognizer list", 52 substrs=[ 53 "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol regex bar", 54 "0: recognizer.MyFrameRecognizer, module a.out, demangled symbol foo", 55 ], 56 ) 57 58 self.runCmd("frame recognizer delete 0") 59 60 # Test that it deleted the recognizer with id 0. 61 self.expect( 62 "frame recognizer list", 63 substrs=[ 64 "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol regex bar" 65 ], 66 ) 67 self.expect( 68 "frame recognizer list", matching=False, substrs=["MyFrameRecognizer"] 69 ) 70 71 # Test that an invalid index and deleting the same index again 72 # is an error and doesn't do any changes. 73 self.expect( 74 "frame recognizer delete 2", 75 error=True, 76 substrs=["error: '2' is not a valid recognizer id."], 77 ) 78 self.expect( 79 "frame recognizer delete 0", 80 error=True, 81 substrs=["error: '0' is not a valid recognizer id."], 82 ) 83 # Recognizers should have the same state as above. 84 self.expect( 85 "frame recognizer list", 86 substrs=[ 87 "1: recognizer.MyOtherFrameRecognizer, module a.out, demangled symbol regex bar" 88 ], 89 ) 90 self.expect( 91 "frame recognizer list", matching=False, substrs=["MyFrameRecognizer"] 92 ) 93 94 self.runCmd("frame recognizer clear") 95 96 self.expect("frame recognizer list", substrs=["no matching results found."]) 97 98 self.runCmd( 99 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo" 100 ) 101 102 self.expect("frame variable", substrs=["(int) a = 42", "(int) b = 56"]) 103 104 # Recognized arguments don't show up by default... 105 variables = frame.GetVariables(lldb.SBVariablesOptions()) 106 self.assertEqual(variables.GetSize(), 0) 107 108 # ...unless you set target.display-recognized-arguments to 1... 109 self.runCmd("settings set target.display-recognized-arguments 1") 110 variables = frame.GetVariables(lldb.SBVariablesOptions()) 111 self.assertEqual(variables.GetSize(), 2) 112 113 # ...and you can reset it back to 0 to hide them again... 114 self.runCmd("settings set target.display-recognized-arguments 0") 115 variables = frame.GetVariables(lldb.SBVariablesOptions()) 116 self.assertEqual(variables.GetSize(), 0) 117 118 # ... or explicitly ask for them with SetIncludeRecognizedArguments(True). 119 opts = lldb.SBVariablesOptions() 120 opts.SetIncludeRecognizedArguments(True) 121 variables = frame.GetVariables(opts) 122 123 self.assertEqual(variables.GetSize(), 2) 124 self.assertEqual(variables.GetValueAtIndex(0).name, "a") 125 self.assertEqual(variables.GetValueAtIndex(0).signed, 42) 126 self.assertEqual( 127 variables.GetValueAtIndex(0).GetValueType(), lldb.eValueTypeVariableArgument 128 ) 129 self.assertEqual(variables.GetValueAtIndex(1).name, "b") 130 self.assertEqual(variables.GetValueAtIndex(1).signed, 56) 131 self.assertEqual( 132 variables.GetValueAtIndex(1).GetValueType(), lldb.eValueTypeVariableArgument 133 ) 134 135 self.expect( 136 "frame recognizer info 0", 137 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 138 ) 139 140 self.expect( 141 "frame recognizer info 999", error=True, substrs=["no frame with index 999"] 142 ) 143 144 self.expect( 145 "frame recognizer info 1", 146 substrs=["frame 1 not recognized by any recognizer"], 147 ) 148 149 # FIXME: The following doesn't work yet, but should be fixed. 150 """ 151 target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", 152 exe_name = exe) 153 frame = thread.GetSelectedFrame() 154 155 self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, 156 substrs=['stopped', 'stop reason = breakpoint']) 157 158 self.expect("frame variable -t", 159 substrs=['(int *) a = ']) 160 161 self.expect("frame variable -t *a", 162 substrs=['*a = 78']) 163 """ 164 165 def test_frame_recognizer_hiding(self): 166 self.build() 167 168 target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "nested") 169 frame = thread.selected_frame 170 171 # Sanity check. 172 self.expect( 173 "thread backtrace", patterns=["frame.*nested", "frame.*baz", "frame.*main"] 174 ) 175 176 self.expect("frame recognizer clear") 177 self.expect( 178 "command script import " 179 + os.path.join(self.getSourceDir(), "recognizer.py") 180 ) 181 182 self.expect( 183 "frame recognizer add -l recognizer.BazFrameRecognizer -f false -s a.out -n baz" 184 ) 185 186 self.expect( 187 "frame recognizer list", 188 substrs=["0: recognizer.BazFrameRecognizer"], 189 ) 190 191 # Now main should be hidden. 192 self.expect("thread backtrace", matching=False, patterns=["frame.*baz"]) 193 self.assertFalse(frame.IsHidden()) 194 frame = thread.SetSelectedFrame(1) 195 self.assertIn("baz", frame.name) 196 self.assertTrue(frame.IsHidden()) 197 198 # Test StepOut. 199 frame = thread.SetSelectedFrame(0) 200 thread.StepOut() 201 frame = thread.GetSelectedFrame() 202 self.assertIn("main", frame.name) 203 204 def test_frame_recognizer_multi_symbol(self): 205 self.build() 206 exe = self.getBuildArtifact("a.out") 207 208 # Clear internal & plugins recognizers that get initialized at launch 209 self.runCmd("frame recognizer clear") 210 211 self.runCmd( 212 "command script import " 213 + os.path.join(self.getSourceDir(), "recognizer.py") 214 ) 215 216 self.expect("frame recognizer list", substrs=["no matching results found."]) 217 218 self.runCmd( 219 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar" 220 ) 221 222 self.expect( 223 "frame recognizer list", 224 substrs=[ 225 "recognizer.MyFrameRecognizer, module a.out, demangled symbol foo, bar" 226 ], 227 ) 228 229 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 230 self, "foo", exe_name=exe 231 ) 232 233 self.expect( 234 "frame recognizer info 0", 235 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 236 ) 237 238 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 239 self, "bar", exe_name=exe 240 ) 241 242 self.expect( 243 "frame recognizer info 0", 244 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 245 ) 246 247 def test_frame_recognizer_target_specific(self): 248 self.build() 249 exe = self.getBuildArtifact("a.out") 250 251 # Clear internal & plugins recognizers that get initialized at launch 252 self.runCmd("frame recognizer clear") 253 254 # Create a target. 255 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 256 self, "foo", exe_name=exe 257 ) 258 259 self.runCmd( 260 "command script import " 261 + os.path.join(self.getSourceDir(), "recognizer.py") 262 ) 263 264 # Check that this doesn't contain our own FrameRecognizer somehow. 265 self.expect( 266 "frame recognizer list", matching=False, substrs=["MyFrameRecognizer"] 267 ) 268 269 # Add a frame recognizer in that target. 270 self.runCmd( 271 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar" 272 ) 273 274 self.expect( 275 "frame recognizer list", 276 substrs=[ 277 "recognizer.MyFrameRecognizer, module a.out, demangled symbol foo, bar" 278 ], 279 ) 280 281 self.expect( 282 "frame recognizer info 0", 283 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 284 ) 285 286 # Create a second target. That one shouldn't have the frame recognizer. 287 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 288 self, "bar", exe_name=exe 289 ) 290 291 self.expect( 292 "frame recognizer info 0", 293 substrs=["frame 0 not recognized by any recognizer"], 294 ) 295 296 # Add a frame recognizer to the new target. 297 self.runCmd( 298 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n bar" 299 ) 300 301 self.expect( 302 "frame recognizer list", 303 substrs=[ 304 "recognizer.MyFrameRecognizer, module a.out, demangled symbol bar" 305 ], 306 ) 307 308 # Now the new target should also recognize the frame. 309 self.expect( 310 "frame recognizer info 0", 311 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 312 ) 313 314 def test_frame_recognizer_not_only_first_instruction(self): 315 self.build() 316 exe = self.getBuildArtifact("a.out") 317 318 # Clear internal & plugins recognizers that get initialized at launch. 319 self.runCmd("frame recognizer clear") 320 321 self.runCmd( 322 "command script import " 323 + os.path.join(self.getSourceDir(), "recognizer.py") 324 ) 325 326 self.expect("frame recognizer list", substrs=["no matching results found."]) 327 328 # Create a target. 329 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 330 self, "foo", exe_name=exe 331 ) 332 333 # Move the PC one instruction further. 334 self.runCmd("next") 335 336 # Add a frame recognizer in that target. 337 self.runCmd( 338 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar" 339 ) 340 341 # It's not applied to foo(), because frame's PC is not at the first instruction of the function. 342 self.expect( 343 "frame recognizer info 0", 344 substrs=["frame 0 not recognized by any recognizer"], 345 ) 346 347 # Add a frame recognizer with --first-instruction-only=true. 348 self.runCmd("frame recognizer clear") 349 350 self.runCmd( 351 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar --first-instruction-only=true" 352 ) 353 354 # It's not applied to foo(), because frame's PC is not at the first instruction of the function. 355 self.expect( 356 "frame recognizer info 0", 357 substrs=["frame 0 not recognized by any recognizer"], 358 ) 359 360 # Now add a frame recognizer with --first-instruction-only=false. 361 self.runCmd("frame recognizer clear") 362 363 self.runCmd( 364 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar --first-instruction-only=false" 365 ) 366 367 # This time it should recognize the frame. 368 self.expect( 369 "frame recognizer info 0", 370 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 371 ) 372 373 opts = lldb.SBVariablesOptions() 374 opts.SetIncludeRecognizedArguments(True) 375 frame = thread.selected_frame 376 variables = frame.GetVariables(opts) 377 378 self.assertEqual(variables.GetSize(), 2) 379 self.assertEqual(variables.GetValueAtIndex(0).name, "a") 380 self.assertEqual(variables.GetValueAtIndex(0).signed, 42) 381 self.assertEqual( 382 variables.GetValueAtIndex(0).GetValueType(), lldb.eValueTypeVariableArgument 383 ) 384 self.assertEqual(variables.GetValueAtIndex(1).name, "b") 385 self.assertEqual(variables.GetValueAtIndex(1).signed, 56) 386 self.assertEqual( 387 variables.GetValueAtIndex(1).GetValueType(), lldb.eValueTypeVariableArgument 388 ) 389 390 def test_frame_recognizer_disable(self): 391 self.build() 392 exe = self.getBuildArtifact("a.out") 393 target, process, thread, _ = lldbutil.run_to_name_breakpoint( 394 self, "foo", exe_name=exe 395 ) 396 397 # Clear internal & plugins recognizers that get initialized at launch. 398 self.runCmd("frame recognizer clear") 399 400 self.runCmd( 401 "command script import " 402 + os.path.join(self.getSourceDir(), "recognizer.py") 403 ) 404 405 # Add a frame recognizer in that target. 406 self.runCmd( 407 "frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar" 408 ) 409 410 # The frame is recognized 411 self.expect( 412 "frame recognizer info 0", 413 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 414 ) 415 416 # Disable the recognizer 417 self.runCmd("frame recognizer disable 0") 418 419 self.expect( 420 "frame recognizer list", 421 substrs=[ 422 "0: [disabled] recognizer.MyFrameRecognizer, module a.out, demangled symbol foo" 423 ], 424 ) 425 426 self.expect( 427 "frame recognizer info 0", 428 substrs=["frame 0 not recognized by any recognizer"], 429 ) 430 431 # Re-enable the recognizer 432 self.runCmd("frame recognizer enable 0") 433 434 self.expect( 435 "frame recognizer list", 436 substrs=[ 437 "0: recognizer.MyFrameRecognizer, module a.out, demangled symbol foo" 438 ], 439 ) 440 441 self.expect( 442 "frame recognizer info 0", 443 substrs=["frame 0 is recognized by recognizer.MyFrameRecognizer"], 444 ) 445 446 @no_debug_info_test 447 def test_frame_recognizer_delete_invalid_arg(self): 448 self.expect( 449 "frame recognizer delete a", 450 error=True, 451 substrs=["error: 'a' is not a valid recognizer id."], 452 ) 453 self.expect( 454 'frame recognizer delete ""', 455 error=True, 456 substrs=["error: '' is not a valid recognizer id."], 457 ) 458 self.expect( 459 "frame recognizer delete -1", 460 error=True, 461 substrs=["error: '-1' is not a valid recognizer id."], 462 ) 463 self.expect( 464 "frame recognizer delete 4294967297", 465 error=True, 466 substrs=["error: '4294967297' is not a valid recognizer id."], 467 ) 468 469 @no_debug_info_test 470 def test_frame_recognizer_info_invalid_arg(self): 471 self.expect( 472 "frame recognizer info a", 473 error=True, 474 substrs=["error: 'a' is not a valid frame index."], 475 ) 476 self.expect( 477 'frame recognizer info ""', 478 error=True, 479 substrs=["error: '' is not a valid frame index."], 480 ) 481 self.expect( 482 "frame recognizer info -1", 483 error=True, 484 substrs=["error: '-1' is not a valid frame index."], 485 ) 486 self.expect( 487 "frame recognizer info 4294967297", 488 error=True, 489 substrs=["error: '4294967297' is not a valid frame index."], 490 ) 491 492 @no_debug_info_test 493 def test_frame_recognizer_add_invalid_arg(self): 494 self.expect( 495 "frame recognizer add -f", 496 error=True, 497 substrs=["error: last option requires an argument"], 498 ) 499 self.expect( 500 "frame recognizer add -f -1", 501 error=True, 502 substrs=["error: invalid boolean value '-1' passed for -f option"], 503 ) 504 self.expect( 505 "frame recognizer add -f foo", 506 error=True, 507 substrs=["error: invalid boolean value 'foo' passed for -f option"], 508 ) 509