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