1""" 2Test setting breakpoints using a scripted resolver 3""" 4 5import os 6import lldb 7import lldbsuite.test.lldbutil as lldbutil 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10 11 12class TestScriptedResolver(TestBase): 13 NO_DEBUG_INFO_TESTCASE = True 14 15 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") 16 def test_scripted_resolver(self): 17 """Use a scripted resolver to set a by symbol name breakpoint""" 18 self.build() 19 self.do_test() 20 21 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") 22 def test_search_depths(self): 23 """Make sure we are called at the right depths depending on what we return 24 from __get_depth__""" 25 self.build() 26 self.do_test_depths() 27 28 @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528") 29 def test_command_line(self): 30 """Test setting a resolver breakpoint from the command line""" 31 self.build() 32 self.do_test_cli() 33 34 def test_bad_command_lines(self): 35 """Make sure we get appropriate errors when we give invalid key/value 36 options""" 37 self.build() 38 self.do_test_bad_options() 39 40 def test_copy_from_dummy_target(self): 41 """Make sure we don't crash during scripted breakpoint copy from dummy target""" 42 self.build() 43 self.do_test_copy_from_dummy_target() 44 45 def make_target_and_import(self): 46 target = self.make_target() 47 self.import_resolver_script() 48 return target 49 50 def make_target(self): 51 return lldbutil.run_to_breakpoint_make_target(self) 52 53 def import_resolver_script(self): 54 interp = self.dbg.GetCommandInterpreter() 55 error = lldb.SBError() 56 57 script_name = os.path.join(self.getSourceDir(), "resolver.py") 58 source_name = os.path.join(self.getSourceDir(), "main.c") 59 60 command = "command script import " + script_name 61 result = lldb.SBCommandReturnObject() 62 interp.HandleCommand(command, result) 63 self.assertTrue( 64 result.Succeeded(), "com scr imp failed: %s" % (result.GetError()) 65 ) 66 67 def make_extra_args(self): 68 json_string = '{"symbol":"break_on_me", "test1": "value1"}' 69 json_stream = lldb.SBStream() 70 json_stream.Print(json_string) 71 extra_args = lldb.SBStructuredData() 72 error = extra_args.SetFromJSON(json_stream) 73 self.assertSuccess(error, "Error making SBStructuredData") 74 return extra_args 75 76 def do_test(self): 77 """This reads in a python file and sets a breakpoint using it.""" 78 79 target = self.make_target_and_import() 80 extra_args = self.make_extra_args() 81 82 file_list = lldb.SBFileSpecList() 83 module_list = lldb.SBFileSpecList() 84 85 # Make breakpoints with this resolver using different filters, first ones that will take: 86 right = [] 87 # one with no file or module spec - this one should fire: 88 right.append( 89 target.BreakpointCreateFromScript( 90 "resolver.Resolver", extra_args, module_list, file_list 91 ) 92 ) 93 94 # one with the right source file and no module - should also fire: 95 file_list.Append(lldb.SBFileSpec("main.c")) 96 right.append( 97 target.BreakpointCreateFromScript( 98 "resolver.Resolver", extra_args, module_list, file_list 99 ) 100 ) 101 # Make sure the help text shows up in the "break list" output: 102 self.expect( 103 "break list", 104 substrs=["I am a python breakpoint resolver"], 105 msg="Help is listed in break list", 106 ) 107 108 # one with the right source file and right module - should also fire: 109 module_list.Append(lldb.SBFileSpec("a.out")) 110 right.append( 111 target.BreakpointCreateFromScript( 112 "resolver.Resolver", extra_args, module_list, file_list 113 ) 114 ) 115 116 # And one with no source file but the right module: 117 file_list.Clear() 118 right.append( 119 target.BreakpointCreateFromScript( 120 "resolver.Resolver", extra_args, module_list, file_list 121 ) 122 ) 123 124 # Make sure these all got locations: 125 for i in range(0, len(right)): 126 self.assertGreaterEqual( 127 right[i].GetNumLocations(), 1, "Breakpoint %d has no locations." % (i) 128 ) 129 130 # Now some ones that won't take: 131 132 module_list.Clear() 133 file_list.Clear() 134 wrong = [] 135 136 # one with the wrong module - should not fire: 137 module_list.Append(lldb.SBFileSpec("noSuchModule")) 138 wrong.append( 139 target.BreakpointCreateFromScript( 140 "resolver.Resolver", extra_args, module_list, file_list 141 ) 142 ) 143 144 # one with the wrong file - also should not fire: 145 file_list.Clear() 146 module_list.Clear() 147 file_list.Append(lldb.SBFileSpec("noFileOfThisName.xxx")) 148 wrong.append( 149 target.BreakpointCreateFromScript( 150 "resolver.Resolver", extra_args, module_list, file_list 151 ) 152 ) 153 154 # Now make sure the CU level iteration obeys the file filters: 155 file_list.Clear() 156 module_list.Clear() 157 file_list.Append(lldb.SBFileSpec("no_such_file.xxx")) 158 wrong.append( 159 target.BreakpointCreateFromScript( 160 "resolver.ResolverCUDepth", extra_args, module_list, file_list 161 ) 162 ) 163 164 # And the Module filters: 165 file_list.Clear() 166 module_list.Clear() 167 module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib")) 168 wrong.append( 169 target.BreakpointCreateFromScript( 170 "resolver.ResolverCUDepth", extra_args, module_list, file_list 171 ) 172 ) 173 174 # Now make sure the Function level iteration obeys the file filters: 175 file_list.Clear() 176 module_list.Clear() 177 file_list.Append(lldb.SBFileSpec("no_such_file.xxx")) 178 wrong.append( 179 target.BreakpointCreateFromScript( 180 "resolver.ResolverFuncDepth", extra_args, module_list, file_list 181 ) 182 ) 183 184 # And the Module filters: 185 file_list.Clear() 186 module_list.Clear() 187 module_list.Append(lldb.SBFileSpec("NoSuchModule.dylib")) 188 wrong.append( 189 target.BreakpointCreateFromScript( 190 "resolver.ResolverFuncDepth", extra_args, module_list, file_list 191 ) 192 ) 193 194 # Make sure these didn't get locations: 195 for i in range(0, len(wrong)): 196 self.assertEqual( 197 wrong[i].GetNumLocations(), 0, "Breakpoint %d has locations." % (i) 198 ) 199 200 # Now run to main and ensure we hit the breakpoints we should have: 201 202 lldbutil.run_to_breakpoint_do_run(self, target, right[0]) 203 204 # Test the hit counts: 205 for i in range(0, len(right)): 206 self.assertEqual( 207 right[i].GetHitCount(), 1, "Breakpoint %d has the wrong hit count" % (i) 208 ) 209 210 for i in range(0, len(wrong)): 211 self.assertEqual( 212 wrong[i].GetHitCount(), 0, "Breakpoint %d has the wrong hit count" % (i) 213 ) 214 215 def do_test_depths(self): 216 """This test uses a class variable in resolver.Resolver which gets set to 1 if we saw 217 compile unit and 2 if we only saw modules. If the search depth is module, you get passed just 218 the modules with no comp_unit. If the depth is comp_unit you get comp_units. So we can use 219 this to test that our callback gets called at the right depth.""" 220 221 target = self.make_target_and_import() 222 extra_args = self.make_extra_args() 223 224 file_list = lldb.SBFileSpecList() 225 module_list = lldb.SBFileSpecList() 226 module_list.Append(lldb.SBFileSpec("a.out")) 227 228 # Make a breakpoint that has no __get_depth__, check that that is converted to eSearchDepthModule: 229 bkpt = target.BreakpointCreateFromScript( 230 "resolver.Resolver", extra_args, module_list, file_list 231 ) 232 self.assertGreater(bkpt.GetNumLocations(), 0, "Resolver got no locations.") 233 self.expect( 234 "script print(resolver.Resolver.got_files)", 235 substrs=["2"], 236 msg="Was only passed modules", 237 ) 238 239 # Make a breakpoint that asks for modules, check that we didn't get any files: 240 bkpt = target.BreakpointCreateFromScript( 241 "resolver.ResolverModuleDepth", extra_args, module_list, file_list 242 ) 243 self.assertGreater( 244 bkpt.GetNumLocations(), 0, "ResolverModuleDepth got no locations." 245 ) 246 self.expect( 247 "script print(resolver.Resolver.got_files)", 248 substrs=["2"], 249 msg="Was only passed modules", 250 ) 251 252 # Make a breakpoint that asks for compile units, check that we didn't get any files: 253 bkpt = target.BreakpointCreateFromScript( 254 "resolver.ResolverCUDepth", extra_args, module_list, file_list 255 ) 256 self.assertGreater( 257 bkpt.GetNumLocations(), 0, "ResolverCUDepth got no locations." 258 ) 259 self.expect( 260 "script print(resolver.Resolver.got_files)", 261 substrs=["1"], 262 msg="Was passed compile units", 263 ) 264 265 # Make a breakpoint that returns a bad value - we should convert that to "modules" so check that: 266 bkpt = target.BreakpointCreateFromScript( 267 "resolver.ResolverBadDepth", extra_args, module_list, file_list 268 ) 269 self.assertGreater( 270 bkpt.GetNumLocations(), 0, "ResolverBadDepth got no locations." 271 ) 272 self.expect( 273 "script print(resolver.Resolver.got_files)", 274 substrs=["2"], 275 msg="Was only passed modules", 276 ) 277 278 # Make a breakpoint that searches at function depth: 279 bkpt = target.BreakpointCreateFromScript( 280 "resolver.ResolverFuncDepth", extra_args, module_list, file_list 281 ) 282 self.assertGreater( 283 bkpt.GetNumLocations(), 0, "ResolverFuncDepth got no locations." 284 ) 285 self.expect( 286 "script print(resolver.Resolver.got_files)", 287 substrs=["3"], 288 msg="Was only passed modules", 289 ) 290 self.expect( 291 "script print(resolver.Resolver.func_list)", 292 substrs=["test_func", "break_on_me", "main"], 293 msg="Saw all the functions", 294 ) 295 296 def do_test_cli(self): 297 target = self.make_target_and_import() 298 299 lldbutil.run_break_set_by_script( 300 self, "resolver.Resolver", extra_options="-k symbol -v break_on_me" 301 ) 302 303 # Make sure setting a resolver breakpoint doesn't pollute further breakpoint setting 304 # by checking the description of a regular file & line breakpoint to make sure it 305 # doesn't mention the Python Resolver function: 306 bkpt_no = lldbutil.run_break_set_by_file_and_line(self, "main.c", 12) 307 bkpt = target.FindBreakpointByID(bkpt_no) 308 strm = lldb.SBStream() 309 bkpt.GetDescription(strm, False) 310 used_resolver = "I am a python breakpoint resolver" in strm.GetData() 311 self.assertFalse( 312 used_resolver, 313 "Found the resolver description in the file & line breakpoint description.", 314 ) 315 316 # Also make sure the breakpoint was where we expected: 317 bp_loc = bkpt.GetLocationAtIndex(0) 318 bp_sc = bp_loc.GetAddress().GetSymbolContext(lldb.eSymbolContextEverything) 319 bp_se = bp_sc.GetLineEntry() 320 self.assertEqual(bp_se.GetLine(), 12, "Got the right line number") 321 self.assertEqual( 322 bp_se.GetFileSpec().GetFilename(), "main.c", "Got the right filename" 323 ) 324 325 def do_test_bad_options(self): 326 target = self.make_target_and_import() 327 328 self.expect( 329 "break set -P resolver.Resolver -k a_key", 330 error=True, 331 msg="Missing value at end", 332 substrs=['Key: "a_key" missing value'], 333 ) 334 self.expect( 335 "break set -P resolver.Resolver -v a_value", 336 error=True, 337 msg="Missing key at end", 338 substrs=['Value: "a_value" missing matching key'], 339 ) 340 self.expect( 341 "break set -P resolver.Resolver -v a_value -k a_key -v another_value", 342 error=True, 343 msg="Missing key among args", 344 substrs=['Value: "a_value" missing matching key'], 345 ) 346 self.expect( 347 "break set -P resolver.Resolver -k a_key -k a_key -v another_value", 348 error=True, 349 msg="Missing value among args", 350 substrs=['Key: "a_key" missing value'], 351 ) 352 353 def do_test_copy_from_dummy_target(self): 354 # Import breakpoint scripted resolver. 355 self.import_resolver_script() 356 357 # Create a scripted breakpoint. 358 self.runCmd( 359 "breakpoint set -P resolver.Resolver -k symbol -v break_on_me", 360 BREAKPOINT_CREATED, 361 ) 362 363 # This is the function to remove breakpoints from the dummy target 364 # to get a clean state for the next test case. 365 def cleanup(): 366 self.runCmd("breakpoint delete -D -f", check=False) 367 self.runCmd("breakpoint list", check=False) 368 369 # Execute the cleanup function during test case tear down. 370 self.addTearDownHook(cleanup) 371 372 # Check that target creating doesn't crash. 373 target = self.make_target() 374