376 lines · python
1"""2Test setting breakpoints using a scripted resolver3"""4 5import os6import lldb7import lldbsuite.test.lldbutil as lldbutil8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10 11 12class TestScriptedResolver(TestBase):13 NO_DEBUG_INFO_TESTCASE = True14 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 return24 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/value36 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 target49 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_name61 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_args75 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_list91 )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_list99 )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_list113 )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_list121 )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_list141 )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_list151 )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_list161 )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_list171 )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_list181 )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_list191 )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 saw217 compile unit and 2 if we only saw modules. If the search depth is module, you get passed just218 the modules with no comp_unit. If the depth is comp_unit you get comp_units. So we can use219 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_list231 )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 print(f"Made first breakpoint: {bkpt}")239 bkpt = None240 # Make a breakpoint that asks for modules, check that we didn't get any files:241 bkpt = target.BreakpointCreateFromScript(242 "resolver.ResolverModuleDepth", extra_args, module_list, file_list243 )244 print(f"Made Second breakpoint: {bkpt}")245 self.assertGreater(246 bkpt.GetNumLocations(), 0, "ResolverModuleDepth got no locations."247 )248 self.expect(249 "script print(resolver.Resolver.got_files)",250 substrs=["2"],251 msg="Was only passed modules",252 )253 254 # Make a breakpoint that asks for compile units, check that we didn't get any files:255 bkpt = target.BreakpointCreateFromScript(256 "resolver.ResolverCUDepth", extra_args, module_list, file_list257 )258 self.assertGreater(259 bkpt.GetNumLocations(), 0, "ResolverCUDepth got no locations."260 )261 self.expect(262 "script print(resolver.Resolver.got_files)",263 substrs=["1"],264 msg="Was passed compile units",265 )266 267 # Make a breakpoint that returns a bad value - we should convert that to "modules" so check that:268 bkpt = target.BreakpointCreateFromScript(269 "resolver.ResolverBadDepth", extra_args, module_list, file_list270 )271 self.assertGreater(272 bkpt.GetNumLocations(), 0, "ResolverBadDepth got no locations."273 )274 self.expect(275 "script print(resolver.Resolver.got_files)",276 substrs=["2"],277 msg="Was only passed modules",278 )279 280 # Make a breakpoint that searches at function depth:281 bkpt = target.BreakpointCreateFromScript(282 "resolver.ResolverFuncDepth", extra_args, module_list, file_list283 )284 self.assertGreater(285 bkpt.GetNumLocations(), 0, "ResolverFuncDepth got no locations."286 )287 self.expect(288 "script print(resolver.Resolver.got_files)",289 substrs=["3"],290 msg="Was only passed modules",291 )292 self.expect(293 "script print(resolver.Resolver.func_list)",294 substrs=["test_func", "break_on_me", "main"],295 msg="Saw all the functions",296 )297 298 def do_test_cli(self):299 target = self.make_target_and_import()300 301 lldbutil.run_break_set_by_script(302 self, "resolver.Resolver", extra_options="-k symbol -v break_on_me"303 )304 305 # Make sure setting a resolver breakpoint doesn't pollute further breakpoint setting306 # by checking the description of a regular file & line breakpoint to make sure it307 # doesn't mention the Python Resolver function:308 bkpt_no = lldbutil.run_break_set_by_file_and_line(self, "main.c", 12)309 bkpt = target.FindBreakpointByID(bkpt_no)310 strm = lldb.SBStream()311 bkpt.GetDescription(strm, False)312 used_resolver = "I am a python breakpoint resolver" in strm.GetData()313 self.assertFalse(314 used_resolver,315 "Found the resolver description in the file & line breakpoint description.",316 )317 318 # Also make sure the breakpoint was where we expected:319 bp_loc = bkpt.GetLocationAtIndex(0)320 bp_sc = bp_loc.GetAddress().GetSymbolContext(lldb.eSymbolContextEverything)321 bp_se = bp_sc.GetLineEntry()322 self.assertEqual(bp_se.GetLine(), 12, "Got the right line number")323 self.assertEqual(324 bp_se.GetFileSpec().GetFilename(), "main.c", "Got the right filename"325 )326 327 def do_test_bad_options(self):328 target = self.make_target_and_import()329 330 self.expect(331 "break set -P resolver.Resolver -k a_key",332 error=True,333 msg="Missing value at end",334 substrs=['Key: "a_key" missing value'],335 )336 self.expect(337 "break set -P resolver.Resolver -v a_value",338 error=True,339 msg="Missing key at end",340 substrs=['Value: "a_value" missing matching key'],341 )342 self.expect(343 "break set -P resolver.Resolver -v a_value -k a_key -v another_value",344 error=True,345 msg="Missing key among args",346 substrs=['Value: "a_value" missing matching key'],347 )348 self.expect(349 "break set -P resolver.Resolver -k a_key -k a_key -v another_value",350 error=True,351 msg="Missing value among args",352 substrs=['Key: "a_key" missing value'],353 )354 355 def do_test_copy_from_dummy_target(self):356 # Import breakpoint scripted resolver.357 self.import_resolver_script()358 359 # Create a scripted breakpoint.360 self.runCmd(361 "breakpoint set -P resolver.Resolver -k symbol -v break_on_me",362 BREAKPOINT_CREATED,363 )364 365 # This is the function to remove breakpoints from the dummy target366 # to get a clean state for the next test case.367 def cleanup():368 self.runCmd("breakpoint delete -D -f", check=False)369 self.runCmd("breakpoint list", check=False)370 371 # Execute the cleanup function during test case tear down.372 self.addTearDownHook(cleanup)373 374 # Check that target creating doesn't crash.375 target = self.make_target()376