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