1""" 2Test breakpoint serialization. 3""" 4 5import os 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class BreakpointSerialization(TestBase): 13 14 mydir = TestBase.compute_mydir(__file__) 15 NO_DEBUG_INFO_TESTCASE = True 16 17 @add_test_categories(['pyapi']) 18 @skipIfReproducer # side_effect bypasses reproducer 19 def test_resolvers(self): 20 """Use Python APIs to test that we serialize resolvers.""" 21 self.build() 22 self.setup_targets_and_cleanup() 23 self.do_check_resolvers() 24 25 @skipIfReproducer # side_effect bypasses reproducer 26 def test_filters(self): 27 """Use Python APIs to test that we serialize search filters correctly.""" 28 self.build() 29 self.setup_targets_and_cleanup() 30 self.do_check_filters() 31 32 @skipIfReproducer # side_effect bypasses reproducer 33 def test_options(self): 34 """Use Python APIs to test that we serialize breakpoint options correctly.""" 35 self.build() 36 self.setup_targets_and_cleanup() 37 self.do_check_options() 38 39 @skipIfReproducer # side_effect bypasses reproducer 40 def test_appending(self): 41 """Use Python APIs to test that we serialize breakpoint options correctly.""" 42 self.build() 43 self.setup_targets_and_cleanup() 44 self.do_check_appending() 45 46 @skipIfReproducer # side_effect bypasses reproducer 47 def test_name_filters(self): 48 """Use python APIs to test that reading in by name works correctly.""" 49 self.build() 50 self.setup_targets_and_cleanup() 51 self.do_check_names() 52 53 @skipIfReproducer # side_effect bypasses reproducer 54 def test_scripted_extra_args(self): 55 self.build() 56 self.setup_targets_and_cleanup() 57 self.do_check_extra_args() 58 59 def setup_targets_and_cleanup(self): 60 def cleanup (): 61 self.RemoveTempFile(self.bkpts_file_path) 62 63 if self.orig_target.IsValid(): 64 self.dbg.DeleteTarget(self.orig_target) 65 self.dbg.DeleteTarget(self.copy_target) 66 67 self.addTearDownHook(cleanup) 68 self.RemoveTempFile(self.bkpts_file_path) 69 70 exe = self.getBuildArtifact("a.out") 71 72 # Create the targets we are making breakpoints in and copying them to: 73 self.orig_target = self.dbg.CreateTarget(exe) 74 self.assertTrue(self.orig_target, VALID_TARGET) 75 76 self.copy_target = self.dbg.CreateTarget(exe) 77 self.assertTrue(self.copy_target, VALID_TARGET) 78 79 def setUp(self): 80 # Call super's setUp(). 81 TestBase.setUp(self) 82 83 self.bkpts_file_path = self.getBuildArtifact("breakpoints.json") 84 self.bkpts_file_spec = lldb.SBFileSpec(self.bkpts_file_path) 85 86 def check_equivalence(self, source_bps, do_write = True): 87 88 error = lldb.SBError() 89 90 if (do_write): 91 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps) 92 self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) 93 94 copy_bps = lldb.SBBreakpointList(self.copy_target) 95 error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) 96 self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) 97 98 num_source_bps = source_bps.GetSize() 99 num_copy_bps = copy_bps.GetSize() 100 self.assertTrue(num_source_bps == num_copy_bps, "Didn't get same number of input and output breakpoints - orig: %d copy: %d"%(num_source_bps, num_copy_bps)) 101 102 for i in range(0, num_source_bps): 103 source_bp = source_bps.GetBreakpointAtIndex(i) 104 source_desc = lldb.SBStream() 105 source_bp.GetDescription(source_desc, False) 106 source_text = source_desc.GetData() 107 108 # I am assuming here that the breakpoints will get written out in breakpoint ID order, and 109 # read back in ditto. That is true right now, and I can't see any reason to do it differently 110 # but if we do we can go to writing the breakpoints one by one, or sniffing the descriptions to 111 # see which one is which. 112 copy_id = source_bp.GetID() 113 copy_bp = copy_bps.FindBreakpointByID(copy_id) 114 self.assertTrue(copy_bp.IsValid(), "Could not find copy breakpoint %d."%(copy_id)) 115 116 copy_desc = lldb.SBStream() 117 copy_bp.GetDescription(copy_desc, False) 118 copy_text = copy_desc.GetData() 119 120 # These two should be identical. 121 # print ("Source text for %d is %s."%(i, source_text)) 122 self.assertTrue (source_text == copy_text, "Source and dest breakpoints are not identical: \nsource: %s\ndest: %s"%(source_text, copy_text)) 123 124 def do_check_resolvers(self): 125 """Use Python APIs to check serialization of breakpoint resolvers""" 126 127 empty_module_list = lldb.SBFileSpecList() 128 empty_cu_list = lldb.SBFileSpecList() 129 blubby_file_spec = lldb.SBFileSpec(os.path.join(self.getSourceDir(), "blubby.c")) 130 131 # It isn't actually important for these purposes that these breakpoint 132 # actually have locations. 133 source_bps = lldb.SBBreakpointList(self.orig_target) 134 source_bps.Append(self.orig_target.BreakpointCreateByLocation("blubby.c", 666)) 135 # Make sure we do one breakpoint right: 136 self.check_equivalence(source_bps) 137 source_bps.Clear() 138 139 source_bps.Append(self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list)) 140 source_bps.Append(self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, empty_module_list,empty_cu_list)) 141 source_bps.Append(self.orig_target.BreakpointCreateBySourceRegex("dont really care", blubby_file_spec)) 142 143 # And some number greater than one: 144 self.check_equivalence(source_bps) 145 146 def do_check_filters(self): 147 """Use Python APIs to check serialization of breakpoint filters.""" 148 module_list = lldb.SBFileSpecList() 149 module_list.Append(lldb.SBFileSpec("SomeBinary")) 150 module_list.Append(lldb.SBFileSpec("SomeOtherBinary")) 151 152 cu_list = lldb.SBFileSpecList() 153 cu_list.Append(lldb.SBFileSpec("SomeCU.c")) 154 cu_list.Append(lldb.SBFileSpec("AnotherCU.c")) 155 cu_list.Append(lldb.SBFileSpec("ThirdCU.c")) 156 157 blubby_file_spec = lldb.SBFileSpec(os.path.join(self.getSourceDir(), "blubby.c")) 158 159 # It isn't actually important for these purposes that these breakpoint 160 # actually have locations. 161 source_bps = lldb.SBBreakpointList(self.orig_target) 162 bkpt = self.orig_target.BreakpointCreateByLocation(blubby_file_spec, 666, 0, module_list) 163 source_bps.Append(bkpt) 164 165 # Make sure we do one right: 166 self.check_equivalence(source_bps) 167 source_bps.Clear() 168 169 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, module_list, cu_list) 170 source_bps.Append(bkpt) 171 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, module_list, cu_list) 172 source_bps.Append(bkpt) 173 bkpt = self.orig_target.BreakpointCreateBySourceRegex("dont really care", blubby_file_spec) 174 source_bps.Append(bkpt) 175 176 # And some number greater than one: 177 self.check_equivalence(source_bps) 178 179 def do_check_options(self): 180 """Use Python APIs to check serialization of breakpoint options.""" 181 182 empty_module_list = lldb.SBFileSpecList() 183 empty_cu_list = lldb.SBFileSpecList() 184 blubby_file_spec = lldb.SBFileSpec(os.path.join(self.getSourceDir(), "blubby.c")) 185 186 # It isn't actually important for these purposes that these breakpoint 187 # actually have locations. 188 source_bps = lldb.SBBreakpointList(self.orig_target) 189 190 bkpt = self.orig_target.BreakpointCreateByLocation( 191 lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList()) 192 bkpt.SetEnabled(False) 193 bkpt.SetOneShot(True) 194 bkpt.SetThreadID(10) 195 source_bps.Append(bkpt) 196 197 # Make sure we get one right: 198 self.check_equivalence(source_bps) 199 source_bps.Clear() 200 201 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list) 202 bkpt.SetIgnoreCount(10) 203 bkpt.SetThreadName("grubby") 204 source_bps.Append(bkpt) 205 206 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list) 207 bkpt.SetCondition("gonna remove this") 208 bkpt.SetCondition("") 209 source_bps.Append(bkpt) 210 211 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, empty_module_list,empty_cu_list) 212 bkpt.SetCondition("something != something_else") 213 bkpt.SetQueueName("grubby") 214 bkpt.AddName("FirstName") 215 bkpt.AddName("SecondName") 216 bkpt.SetScriptCallbackBody('\tprint("I am a function that prints.")\n\tprint("I don\'t do anything else")\n') 217 source_bps.Append(bkpt) 218 219 bkpt = self.orig_target.BreakpointCreateBySourceRegex("dont really care", blubby_file_spec) 220 cmd_list = lldb.SBStringList() 221 cmd_list.AppendString("frame var") 222 cmd_list.AppendString("thread backtrace") 223 224 bkpt.SetCommandLineCommands(cmd_list) 225 source_bps.Append(bkpt) 226 227 self.check_equivalence(source_bps) 228 229 def do_check_appending(self): 230 """Use Python APIs to check appending to already serialized options.""" 231 232 empty_module_list = lldb.SBFileSpecList() 233 empty_cu_list = lldb.SBFileSpecList() 234 blubby_file_spec = lldb.SBFileSpec(os.path.join(self.getSourceDir(), "blubby.c")) 235 236 # It isn't actually important for these purposes that these breakpoint 237 # actually have locations. 238 239 all_bps = lldb.SBBreakpointList(self.orig_target) 240 source_bps = lldb.SBBreakpointList(self.orig_target) 241 242 bkpt = self.orig_target.BreakpointCreateByLocation( 243 lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList()) 244 bkpt.SetEnabled(False) 245 bkpt.SetOneShot(True) 246 bkpt.SetThreadID(10) 247 source_bps.Append(bkpt) 248 all_bps.Append(bkpt) 249 250 error = lldb.SBError() 251 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps) 252 self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) 253 254 source_bps.Clear() 255 256 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeAuto, empty_module_list, empty_cu_list) 257 bkpt.SetIgnoreCount(10) 258 bkpt.SetThreadName("grubby") 259 source_bps.Append(bkpt) 260 all_bps.Append(bkpt) 261 262 bkpt = self.orig_target.BreakpointCreateByName("blubby", lldb.eFunctionNameTypeFull, empty_module_list,empty_cu_list) 263 bkpt.SetCondition("something != something_else") 264 bkpt.SetQueueName("grubby") 265 bkpt.AddName("FirstName") 266 bkpt.AddName("SecondName") 267 268 source_bps.Append(bkpt) 269 all_bps.Append(bkpt) 270 271 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, source_bps, True) 272 self.assertTrue(error.Success(), "Failed appending breakpoints to file: %s."%(error.GetCString())) 273 274 self.check_equivalence(all_bps) 275 276 def do_check_names(self): 277 bkpt = self.orig_target.BreakpointCreateByLocation( 278 lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList()) 279 good_bkpt_name = "GoodBreakpoint" 280 write_bps = lldb.SBBreakpointList(self.orig_target) 281 bkpt.AddName(good_bkpt_name) 282 write_bps.Append(bkpt) 283 284 error = lldb.SBError() 285 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) 286 self.assertTrue(error.Success(), "Failed writing breakpoints to file: %s."%(error.GetCString())) 287 288 copy_bps = lldb.SBBreakpointList(self.copy_target) 289 names_list = lldb.SBStringList() 290 names_list.AppendString("NoSuchName") 291 292 error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, names_list, copy_bps) 293 self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) 294 self.assertTrue(copy_bps.GetSize() == 0, "Found breakpoints with a nonexistent name.") 295 296 names_list.AppendString(good_bkpt_name) 297 error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, names_list, copy_bps) 298 self.assertTrue(error.Success(), "Failed reading breakpoints from file: %s"%(error.GetCString())) 299 self.assertTrue(copy_bps.GetSize() == 1, "Found the matching breakpoint.") 300 301 def do_check_extra_args(self): 302 303 import side_effect 304 interp = self.dbg.GetCommandInterpreter() 305 error = lldb.SBError() 306 307 script_name = os.path.join(self.getSourceDir(), "resolver.py") 308 309 command = "command script import " + script_name 310 result = lldb.SBCommandReturnObject() 311 interp.HandleCommand(command, result) 312 self.assertTrue(result.Succeeded(), "com scr imp failed: %s"%(result.GetError())) 313 314 # First make sure a scripted breakpoint with no args works: 315 bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver", lldb.SBStructuredData(), 316 lldb.SBFileSpecList(), lldb.SBFileSpecList()) 317 self.assertTrue(bkpt.IsValid(), "Bkpt is valid") 318 write_bps = lldb.SBBreakpointList(self.orig_target) 319 320 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) 321 self.assertTrue(error.Success(), "Failed writing breakpoints: %s"%(error.GetCString())) 322 323 side_effect.g_extra_args = None 324 copy_bps = lldb.SBBreakpointList(self.copy_target) 325 error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) 326 self.assertTrue(error.Success(), "Failed reading breakpoints: %s"%(error.GetCString())) 327 328 self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.") 329 no_keys = lldb.SBStringList() 330 side_effect.g_extra_args.GetKeys(no_keys) 331 self.assertEqual(no_keys.GetSize(), 0, "Should have no keys") 332 333 self.orig_target.DeleteAllBreakpoints() 334 self.copy_target.DeleteAllBreakpoints() 335 336 # Now try one with extra args: 337 338 extra_args = lldb.SBStructuredData() 339 stream = lldb.SBStream() 340 stream.Print('{"first_arg" : "first_value", "second_arg" : "second_value"}') 341 extra_args.SetFromJSON(stream) 342 self.assertTrue(extra_args.IsValid(), "SBStructuredData is valid.") 343 344 bkpt = self.orig_target.BreakpointCreateFromScript("resolver.Resolver", 345 extra_args, lldb.SBFileSpecList(), lldb.SBFileSpecList()) 346 self.assertTrue(bkpt.IsValid(), "Bkpt is valid") 347 write_bps = lldb.SBBreakpointList(self.orig_target) 348 349 error = self.orig_target.BreakpointsWriteToFile(self.bkpts_file_spec, write_bps) 350 self.assertTrue(error.Success(), "Failed writing breakpoints: %s"%(error.GetCString())) 351 352 orig_extra_args = side_effect.g_extra_args 353 self.assertTrue(orig_extra_args.IsValid(), "Extra args originally valid") 354 355 orig_keys = lldb.SBStringList() 356 orig_extra_args.GetKeys(orig_keys) 357 self.assertEqual(2, orig_keys.GetSize(), "Should have two keys") 358 359 side_effect.g_extra_args = None 360 361 copy_bps = lldb.SBBreakpointList(self.copy_target) 362 error = self.copy_target.BreakpointsCreateFromFile(self.bkpts_file_spec, copy_bps) 363 self.assertTrue(error.Success(), "Failed reading breakpoints: %s"%(error.GetCString())) 364 365 self.assertEqual(copy_bps.GetSize(), 1, "Got one breakpoint from file.") 366 367 copy_extra_args = side_effect.g_extra_args 368 copy_keys = lldb.SBStringList() 369 copy_extra_args.GetKeys(copy_keys) 370 self.assertEqual(2, copy_keys.GetSize(), "Copy should have two keys") 371 372 for idx in range(0, orig_keys.GetSize()): 373 key = orig_keys.GetStringAtIndex(idx) 374 copy_value = copy_extra_args.GetValueForKey(key).GetStringValue(100) 375 376 if key == "first_arg": 377 self.assertEqual(copy_value, "first_value") 378 elif key == "second_arg": 379 self.assertEqual(copy_value, "second_value") 380 else: 381 self.Fail("Unknown key: %s"%(key)) 382