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