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