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