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