837 lines · python
1"""2Test lldb-dap variables request3"""4 5import os6 7import lldbdap_testcase8from lldbsuite.test.decorators import *9from lldbsuite.test.lldbtest import *10 11 12def make_buffer_verify_dict(start_idx, count, offset=0):13 verify_dict = {}14 for i in range(start_idx, start_idx + count):15 verify_dict["[%i]" % (i)] = {"type": "int", "value": str(i + offset)}16 return verify_dict17 18 19class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):20 def verify_values(self, verify_dict, actual, varref_dict=None, expression=None):21 if "equals" in verify_dict:22 verify = verify_dict["equals"]23 for key in verify:24 verify_value = verify[key]25 actual_value = actual[key]26 self.assertEqual(27 verify_value,28 actual_value,29 '"%s" keys don\'t match (%s != %s) from:\n%s'30 % (key, actual_value, verify_value, actual),31 )32 if "startswith" in verify_dict:33 verify = verify_dict["startswith"]34 for key in verify:35 verify_value = verify[key]36 actual_value = actual[key]37 startswith = actual_value.startswith(verify_value)38 self.assertTrue(39 startswith,40 ('"%s" value "%s" doesn\'t start with "%s")')41 % (key, actual_value, verify_value),42 )43 if "matches" in verify_dict:44 verify = verify_dict["matches"]45 for key in verify:46 verify_value = verify[key]47 actual_value = actual[key]48 self.assertRegex(49 actual_value,50 verify_value,51 ('"%s" value "%s" doesn\'t match pattern "%s")')52 % (key, actual_value, verify_value),53 )54 if "contains" in verify_dict:55 verify = verify_dict["contains"]56 for key in verify:57 contains_array = verify[key]58 actual_value = actual[key]59 self.assertIsInstance(contains_array, list)60 for verify_value in contains_array:61 self.assertIn(verify_value, actual_value)62 if "missing" in verify_dict:63 missing = verify_dict["missing"]64 for key in missing:65 self.assertNotIn(66 key, actual, 'key "%s" is not expected in %s' % (key, actual)67 )68 isReadOnly = verify_dict.get("readOnly", False)69 attributes = actual.get("presentationHint", {}).get("attributes", [])70 self.assertEqual(71 isReadOnly, "readOnly" in attributes, "%s %s" % (verify_dict, actual)72 )73 hasVariablesReference = "variablesReference" in actual74 varRef = None75 if hasVariablesReference:76 # Remember variable references in case we want to test further77 # by using the evaluate name.78 varRef = actual["variablesReference"]79 if varRef != 0 and varref_dict is not None:80 if expression is None:81 evaluateName = actual["evaluateName"]82 else:83 evaluateName = expression84 varref_dict[evaluateName] = varRef85 if (86 "hasVariablesReference" in verify_dict87 and verify_dict["hasVariablesReference"]88 ):89 self.assertTrue(hasVariablesReference, "verify variable reference")90 if "children" in verify_dict:91 self.assertTrue(92 hasVariablesReference and varRef is not None and varRef != 0,93 ("children verify values specified for " "variable without children"),94 )95 96 response = self.dap_server.request_variables(varRef)97 self.verify_variables(98 verify_dict["children"], response["body"]["variables"], varref_dict99 )100 101 def verify_variables(self, verify_dict, variables, varref_dict=None):102 for variable in variables:103 name = variable["name"]104 if not name.startswith("std::"):105 self.assertIn(106 name, verify_dict, 'variable "%s" in verify dictionary' % (name)107 )108 self.verify_values(verify_dict[name], variable, varref_dict)109 110 def darwin_dwarf_missing_obj(self, initCommands):111 self.build(debug_info="dwarf")112 program = self.getBuildArtifact("a.out")113 main_obj = self.getBuildArtifact("main.o")114 self.assertTrue(os.path.exists(main_obj))115 # Delete the main.o file that contains the debug info so we force an116 # error when we run to main and try to get variables117 os.unlink(main_obj)118 119 self.create_debug_adapter()120 self.assertTrue(os.path.exists(program), "executable must exist")121 122 self.launch(program, initCommands=initCommands)123 124 functions = ["main"]125 breakpoint_ids = self.set_function_breakpoints(functions)126 self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")127 self.continue_to_breakpoints(breakpoint_ids)128 129 locals = self.dap_server.get_local_variables()130 131 verify_locals = {132 "<error>": {133 "equals": {"type": "const char *"},134 "contains": {135 "value": [136 "debug map object file ",137 'main.o" containing debug info does not exist, debug info will not be loaded',138 ]139 },140 },141 }142 varref_dict = {}143 self.verify_variables(verify_locals, locals, varref_dict)144 145 def do_test_scopes_variables_setVariable_evaluate(146 self, enableAutoVariableSummaries: bool147 ):148 """149 Tests the "scopes", "variables", "setVariable", and "evaluate" packets.150 """151 program = self.getBuildArtifact("a.out")152 self.build_and_launch(153 program, enableAutoVariableSummaries=enableAutoVariableSummaries154 )155 source = "main.cpp"156 breakpoint1_line = line_number(source, "// breakpoint 1")157 lines = [breakpoint1_line]158 # Set breakpoint in the thread function so we can step the threads159 breakpoint_ids = self.set_source_breakpoints(source, lines)160 self.assertEqual(161 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"162 )163 self.continue_to_breakpoints(breakpoint_ids)164 locals = self.dap_server.get_local_variables()165 globals = self.dap_server.get_global_variables()166 buffer_children = make_buffer_verify_dict(0, 16)167 verify_locals = {168 "argc": {169 "equals": {170 "type": "int",171 "value": "1",172 },173 },174 "argv": {175 "equals": {"type": "const char **"},176 "startswith": {"value": "0x"},177 "hasVariablesReference": True,178 },179 "pt": {180 "equals": {181 "type": "PointType",182 },183 "hasVariablesReference": True,184 "children": {185 "x": {"equals": {"type": "int", "value": "11"}},186 "y": {"equals": {"type": "int", "value": "22"}},187 "buffer": {"children": buffer_children, "readOnly": True},188 },189 "readOnly": True,190 },191 "x": {"equals": {"type": "int"}},192 }193 194 verify_globals = {195 "s_local": {"equals": {"type": "float", "value": "2.25"}},196 }197 s_global = {"equals": {"type": "int", "value": "234"}}198 g_global = {"equals": {"type": "int", "value": "123"}}199 if lldbplatformutil.getHostPlatform() == "windows":200 verify_globals["::s_global"] = s_global201 verify_globals["g_global"] = g_global202 else:203 verify_globals["s_global"] = s_global204 verify_globals["::g_global"] = g_global205 206 varref_dict = {}207 self.verify_variables(verify_locals, locals, varref_dict)208 self.verify_variables(verify_globals, globals, varref_dict)209 # pprint.PrettyPrinter(indent=4).pprint(varref_dict)210 # We need to test the functionality of the "variables" request as it211 # has optional parameters like "start" and "count" to limit the number212 # of variables that are fetched213 varRef = varref_dict["pt.buffer"]214 response = self.dap_server.request_variables(varRef)215 self.verify_variables(buffer_children, response["body"]["variables"])216 # Verify setting start=0 in the arguments still gets all children217 response = self.dap_server.request_variables(varRef, start=0)218 self.verify_variables(buffer_children, response["body"]["variables"])219 # Verify setting count=0 in the arguments still gets all children.220 # If count is zero, it means to get all children.221 response = self.dap_server.request_variables(varRef, count=0)222 self.verify_variables(buffer_children, response["body"]["variables"])223 # Verify setting count to a value that is too large in the arguments224 # still gets all children, and no more225 response = self.dap_server.request_variables(varRef, count=1000)226 self.verify_variables(buffer_children, response["body"]["variables"])227 # Verify setting the start index and count gets only the children we228 # want229 response = self.dap_server.request_variables(varRef, start=5, count=5)230 self.verify_variables(231 make_buffer_verify_dict(5, 5), response["body"]["variables"]232 )233 # Verify setting the start index to a value that is out of range234 # results in an empty list235 response = self.dap_server.request_variables(varRef, start=32, count=1)236 self.assertEqual(237 len(response["body"]["variables"]),238 0,239 "verify we get no variable back for invalid start",240 )241 242 # Test evaluate243 expressions = {244 "pt.x": {245 "equals": {"result": "11", "type": "int"},246 "hasVariablesReference": False,247 },248 "pt.buffer[2]": {249 "equals": {"result": "2", "type": "int"},250 "hasVariablesReference": False,251 },252 "pt": {253 "equals": {"type": "PointType"},254 "startswith": {255 "result": (256 "{x:11, y:22, buffer:{...}}"257 if enableAutoVariableSummaries258 else "PointType @ 0x"259 )260 },261 "hasVariablesReference": True,262 },263 "pt.buffer": {264 "equals": {"type": "int[16]"},265 "startswith": {266 "result": (267 "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"268 if enableAutoVariableSummaries269 else "int[16] @ 0x"270 )271 },272 "hasVariablesReference": True,273 },274 "argv": {275 "equals": {"type": "const char **"},276 "startswith": {"result": "0x"},277 "hasVariablesReference": True,278 },279 "argv[0]": {280 "equals": {"type": "const char *"},281 "startswith": {"result": "0x"},282 "hasVariablesReference": True,283 },284 "2+3": {285 "equals": {"result": "5", "type": "int"},286 "hasVariablesReference": False,287 },288 }289 for expression in expressions:290 response = self.dap_server.request_evaluate(expression)291 self.verify_values(expressions[expression], response["body"])292 293 # Test setting variables294 self.set_local("argc", 123)295 argc = self.get_local_as_int("argc")296 self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % (argc))297 298 self.set_local("argv", 0x1234)299 argv = self.get_local_as_int("argv")300 self.assertEqual(301 argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % (argv)302 )303 304 # Set a variable value whose name is synthetic, like a variable index305 # and verify the value by reading it306 variable_value = 100307 response = self.set_variable(varRef, "[0]", variable_value)308 # Verify dap sent the correct response309 verify_response = {310 "type": "int",311 "value": str(variable_value),312 }313 for key, value in verify_response.items():314 self.assertEqual(value, response["body"][key])315 316 response = self.dap_server.request_variables(varRef, start=0, count=1)317 self.verify_variables(318 make_buffer_verify_dict(0, 1, variable_value), response["body"]["variables"]319 )320 321 # Set a variable value whose name is a real child value, like "pt.x"322 # and verify the value by reading it323 varRef = varref_dict["pt"]324 self.set_variable(varRef, "x", 111)325 response = self.dap_server.request_variables(varRef, start=0, count=1)326 value = response["body"]["variables"][0]["value"]327 self.assertEqual(328 value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)329 )330 331 # We check shadowed variables and that a new get_local_variables request332 # gets the right data333 breakpoint2_line = line_number(source, "// breakpoint 2")334 lines = [breakpoint2_line]335 breakpoint_ids = self.set_source_breakpoints(source, lines)336 self.assertEqual(337 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"338 )339 self.continue_to_breakpoints(breakpoint_ids)340 341 verify_locals["argc"]["equals"]["value"] = "123"342 verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"343 verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "89"}}344 verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "42"}}345 verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "72"}}346 347 self.verify_variables(verify_locals, self.dap_server.get_local_variables())348 349 # Now we verify that we correctly change the name of a variable with and without differentiator suffix350 self.assertFalse(self.set_local("x2", 9)["success"])351 self.assertFalse(self.set_local("x @ main.cpp:0", 9)["success"])352 353 self.assertTrue(self.set_local("x @ main.cpp:19", 19)["success"])354 self.assertTrue(self.set_local("x @ main.cpp:21", 21)["success"])355 self.assertTrue(self.set_local("x @ main.cpp:23", 23)["success"])356 357 # The following should have no effect358 self.assertFalse(self.set_local("x @ main.cpp:23", "invalid")["success"])359 360 verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"361 verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"362 verify_locals["x @ main.cpp:23"]["equals"]["value"] = "23"363 364 self.verify_variables(verify_locals, self.dap_server.get_local_variables())365 366 # The plain x variable shold refer to the innermost x367 self.assertTrue(self.set_local("x", 22)["success"])368 verify_locals["x @ main.cpp:23"]["equals"]["value"] = "22"369 370 self.verify_variables(verify_locals, self.dap_server.get_local_variables())371 372 # In breakpoint 3, there should be no shadowed variables373 breakpoint3_line = line_number(source, "// breakpoint 3")374 lines = [breakpoint3_line]375 breakpoint_ids = self.set_source_breakpoints(source, lines)376 self.assertEqual(377 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"378 )379 self.continue_to_breakpoints(breakpoint_ids)380 381 locals = self.dap_server.get_local_variables()382 names = [var["name"] for var in locals]383 # The first shadowed x shouldn't have a suffix anymore384 verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}385 self.assertNotIn("x @ main.cpp:19", names)386 self.assertNotIn("x @ main.cpp:21", names)387 self.assertNotIn("x @ main.cpp:23", names)388 389 self.verify_variables(verify_locals, locals)390 391 @skipIfWindows392 def test_scopes_variables_setVariable_evaluate(self):393 self.do_test_scopes_variables_setVariable_evaluate(394 enableAutoVariableSummaries=False395 )396 397 @skipIfWindows398 def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):399 self.do_test_scopes_variables_setVariable_evaluate(400 enableAutoVariableSummaries=True401 )402 403 @skipIfWindows404 def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):405 """406 Tests the evaluated expression expands successfully after "scopes" packets407 and permanent expressions persist.408 """409 program = self.getBuildArtifact("a.out")410 self.build_and_launch(411 program, enableAutoVariableSummaries=enableAutoVariableSummaries412 )413 source = "main.cpp"414 breakpoint1_line = line_number(source, "// breakpoint 1")415 lines = [breakpoint1_line]416 # Set breakpoint in the thread function so we can step the threads417 breakpoint_ids = self.set_source_breakpoints(source, lines)418 self.assertEqual(419 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"420 )421 self.continue_to_breakpoints(breakpoint_ids)422 423 # Verify locals424 locals = self.dap_server.get_local_variables()425 buffer_children = make_buffer_verify_dict(0, 32)426 verify_locals = {427 "argc": {428 "equals": {"type": "int", "value": "1"},429 "missing": ["indexedVariables"],430 },431 "argv": {432 "equals": {"type": "const char **"},433 "startswith": {"value": "0x"},434 "hasVariablesReference": True,435 "missing": ["indexedVariables"],436 },437 "pt": {438 "equals": {"type": "PointType"},439 "hasVariablesReference": True,440 "missing": ["indexedVariables"],441 "children": {442 "x": {443 "equals": {"type": "int", "value": "11"},444 "missing": ["indexedVariables"],445 },446 "y": {447 "equals": {"type": "int", "value": "22"},448 "missing": ["indexedVariables"],449 },450 "buffer": {451 "children": buffer_children,452 "equals": {"indexedVariables": 16},453 "readOnly": True,454 },455 },456 "readOnly": True,457 },458 "x": {459 "equals": {"type": "int"},460 "missing": ["indexedVariables"],461 },462 }463 self.verify_variables(verify_locals, locals)464 465 # Evaluate expandable expression twice: once permanent (from repl)466 # the other temporary (from other UI).467 expandable_expression = {468 "name": "pt",469 "context": {470 "repl": {471 "equals": {"type": "PointType"},472 "equals": {473 "result": """(PointType) $0 = {474 x = 11475 y = 22476 buffer = {477 [0] = 0478 [1] = 1479 [2] = 2480 [3] = 3481 [4] = 4482 [5] = 5483 [6] = 6484 [7] = 7485 [8] = 8486 [9] = 9487 [10] = 10488 [11] = 11489 [12] = 12490 [13] = 13491 [14] = 14492 [15] = 15493 }494}"""495 },496 "missing": ["indexedVariables"],497 "hasVariablesReference": True,498 },499 "hover": {500 "equals": {"type": "PointType"},501 "startswith": {502 "result": (503 "{x:11, y:22, buffer:{...}}"504 if enableAutoVariableSummaries505 else "PointType @ 0x"506 )507 },508 "missing": ["indexedVariables"],509 "hasVariablesReference": True,510 },511 "watch": {512 "equals": {"type": "PointType"},513 "startswith": {514 "result": (515 "{x:11, y:22, buffer:{...}}"516 if enableAutoVariableSummaries517 else "PointType @ 0x"518 )519 },520 "missing": ["indexedVariables"],521 "hasVariablesReference": True,522 },523 "variables": {524 "equals": {"type": "PointType"},525 "startswith": {526 "result": (527 "{x:11, y:22, buffer:{...}}"528 if enableAutoVariableSummaries529 else "PointType @ 0x"530 )531 },532 "missing": ["indexedVariables"],533 "hasVariablesReference": True,534 },535 },536 "children": {537 "x": {"equals": {"type": "int", "value": "11"}},538 "y": {"equals": {"type": "int", "value": "22"}},539 "buffer": {"children": buffer_children, "readOnly": True},540 },541 }542 543 # Evaluate from known contexts.544 expr_varref_dict = {}545 for context, verify_dict in expandable_expression["context"].items():546 response = self.dap_server.request_evaluate(547 expandable_expression["name"],548 frameIndex=0,549 threadId=None,550 context=context,551 )552 self.verify_values(553 verify_dict,554 response["body"],555 expr_varref_dict,556 expandable_expression["name"],557 )558 559 # Evaluate locals again.560 locals = self.dap_server.get_local_variables()561 self.verify_variables(verify_locals, locals)562 563 # Verify the evaluated expressions before second locals evaluation564 # can be expanded.565 var_ref = expr_varref_dict[expandable_expression["name"]]566 response = self.dap_server.request_variables(var_ref)567 self.verify_variables(568 expandable_expression["children"], response["body"]["variables"]569 )570 571 # Continue to breakpoint 3, permanent variable should still exist572 # after resume.573 breakpoint3_line = line_number(source, "// breakpoint 3")574 lines = [breakpoint3_line]575 breakpoint_ids = self.set_source_breakpoints(source, lines)576 self.assertEqual(577 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"578 )579 self.continue_to_breakpoints(breakpoint_ids)580 581 var_ref = expr_varref_dict[expandable_expression["name"]]582 response = self.dap_server.request_variables(var_ref)583 self.verify_variables(584 expandable_expression["children"], response["body"]["variables"]585 )586 587 # Test that frame scopes have corresponding presentation hints.588 frame_id = self.dap_server.get_stackFrame()["id"]589 scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]590 591 scope_names = [scope["name"] for scope in scopes]592 self.assertIn("Locals", scope_names)593 self.assertIn("Registers", scope_names)594 595 for scope in scopes:596 if scope["name"] == "Locals":597 self.assertEqual(scope.get("presentationHint"), "locals")598 if scope["name"] == "Registers":599 self.assertEqual(scope.get("presentationHint"), "registers")600 601 def test_scopes_and_evaluate_expansion(self):602 self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)603 604 def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):605 self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)606 607 def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):608 """609 Tests that arrays and lldb.SBValue objects that have synthetic child610 providers have "indexedVariables" key/value pairs. This helps the IDE611 not to fetch too many children all at once.612 """613 program = self.getBuildArtifact("a.out")614 self.build_and_launch(615 program, enableSyntheticChildDebugging=enableSyntheticChildDebugging616 )617 source = "main.cpp"618 breakpoint1_line = line_number(source, "// breakpoint 4")619 lines = [breakpoint1_line]620 # Set breakpoint in the thread function so we can step the threads621 breakpoint_ids = self.set_source_breakpoints(source, lines)622 self.assertEqual(623 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"624 )625 self.continue_to_breakpoints(breakpoint_ids)626 627 # Verify locals628 locals = self.dap_server.get_local_variables()629 # The vector variables might have one additional entry from the fake630 # "[raw]" child.631 raw_child_count = 1 if enableSyntheticChildDebugging else 0632 verify_locals = {633 "small_array": {"equals": {"indexedVariables": 5}, "readOnly": True},634 "large_array": {"equals": {"indexedVariables": 200}, "readOnly": True},635 "small_vector": {636 "equals": {"indexedVariables": 5 + raw_child_count},637 "readOnly": True,638 },639 "large_vector": {640 "equals": {"indexedVariables": 200 + raw_child_count},641 "readOnly": True,642 },643 "pt": {"missing": ["indexedVariables"], "readOnly": True},644 }645 self.verify_variables(verify_locals, locals)646 647 # We also verify that we produce a "[raw]" fake child with the real648 # SBValue for the synthetic type.649 verify_children = {650 "[0]": {"equals": {"type": "int", "value": "0"}},651 "[1]": {"equals": {"type": "int", "value": "0"}},652 "[2]": {"equals": {"type": "int", "value": "0"}},653 "[3]": {"equals": {"type": "int", "value": "0"}},654 "[4]": {"equals": {"type": "int", "value": "0"}},655 }656 if enableSyntheticChildDebugging:657 verify_children["[raw]"] = {658 "contains": {"type": ["vector"]},659 "readOnly": True,660 }661 662 children = self.dap_server.request_variables(locals[2]["variablesReference"])[663 "body"664 ]["variables"]665 self.verify_variables(verify_children, children)666 667 @skipIfWindows668 def test_return_variables(self):669 """670 Test the stepping out of a function with return value show the variable correctly.671 """672 program = self.getBuildArtifact("a.out")673 self.build_and_launch(program)674 675 return_name = "(Return Value)"676 verify_locals = {677 return_name: {"equals": {"type": "int", "value": "300"}},678 "argc": {},679 "argv": {},680 "pt": {"readOnly": True},681 "x": {},682 "return_result": {"equals": {"type": "int"}},683 }684 685 function_name = "test_return_variable"686 breakpoint_ids = self.set_function_breakpoints([function_name])687 688 self.assertEqual(len(breakpoint_ids), 1)689 self.continue_to_breakpoints(breakpoint_ids)690 691 threads = self.dap_server.get_threads()692 for thread in threads:693 if thread.get("reason") == "breakpoint":694 thread_id = thread["id"]695 696 self.stepOut(threadId=thread_id)697 698 local_variables = self.dap_server.get_local_variables()699 varref_dict = {}700 701 # `verify_variable` function only checks if the local variables702 # are in the `verify_dict` passed this will cause this test to pass703 # even if there is no return value.704 local_variable_names = [705 variable["name"] for variable in local_variables706 ]707 self.assertIn(708 return_name,709 local_variable_names,710 "return variable is not in local variables",711 )712 713 self.verify_variables(verify_locals, local_variables, varref_dict)714 break715 716 self.assertFalse(self.set_local("(Return Value)", 20)["success"])717 718 @skipIfWindows719 def test_indexedVariables(self):720 self.do_test_indexedVariables(enableSyntheticChildDebugging=False)721 722 @skipIfWindows723 def test_indexedVariables_with_raw_child_for_synthetics(self):724 self.do_test_indexedVariables(enableSyntheticChildDebugging=True)725 726 @skipIfWindows727 @skipIfAsan # FIXME this fails with a non-asan issue on green dragon.728 def test_registers(self):729 """730 Test that registers whose byte size is the size of a pointer on731 the current system get formatted as lldb::eFormatAddressInfo. This732 will show the pointer value followed by a description of the address733 itself. To test this we attempt to find the PC value in the general734 purpose registers, and since we will be stopped in main.cpp, verify735 that the value for the PC starts with a pointer and is followed by736 a description that contains main.cpp.737 """738 program = self.getBuildArtifact("a.out")739 self.build_and_launch(program)740 source = "main.cpp"741 breakpoint1_line = line_number(source, "// breakpoint 1")742 lines = [breakpoint1_line]743 # Set breakpoint in the thread function so we can step the threads744 breakpoint_ids = self.set_source_breakpoints(source, lines)745 self.assertEqual(746 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"747 )748 self.continue_to_breakpoints(breakpoint_ids)749 750 pc_name = None751 arch = self.getArchitecture()752 if arch == "x86_64":753 pc_name = "rip"754 elif arch == "x86":755 pc_name = "rip"756 elif arch.startswith("arm"):757 pc_name = "pc"758 759 if pc_name is None:760 return761 # Verify locals762 reg_sets = self.dap_server.get_registers()763 for reg_set in reg_sets:764 if reg_set["name"] == "General Purpose Registers":765 varRef = reg_set["variablesReference"]766 regs = self.dap_server.request_variables(varRef)["body"]["variables"]767 for reg in regs:768 if reg["name"] == pc_name:769 value = reg["value"]770 self.assertTrue(value.startswith("0x"))771 self.assertIn("a.out`main + ", value)772 self.assertIn("at main.cpp:", value)773 774 @no_debug_info_test775 @skipUnlessDarwin776 def test_darwin_dwarf_missing_obj(self):777 """778 Test that if we build a binary with DWARF in .o files and we remove779 the .o file for main.cpp, that we get a variable named "<error>"780 whose value matches the appriopriate error. Errors when getting781 variables are returned in the LLDB API when the user should be782 notified of issues that can easily be solved by rebuilding or783 changing compiler options and are designed to give better feedback784 to the user.785 """786 self.darwin_dwarf_missing_obj(None)787 788 @no_debug_info_test789 @skipUnlessDarwin790 def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):791 """792 Test that if we build a binary with DWARF in .o files and we remove793 the .o file for main.cpp, that we get a variable named "<error>"794 whose value matches the appriopriate error. Test with symbol_ondemand_enabled.795 """796 initCommands = ["settings set symbols.load-on-demand true"]797 self.darwin_dwarf_missing_obj(initCommands)798 799 @no_debug_info_test800 @skipIfWindows801 def test_value_format(self):802 """803 Test that toggle variables value format between decimal and hexical works.804 """805 program = self.getBuildArtifact("a.out")806 self.build_and_launch(program)807 source = "main.cpp"808 breakpoint1_line = line_number(source, "// breakpoint 1")809 lines = [breakpoint1_line]810 811 breakpoint_ids = self.set_source_breakpoints(source, lines)812 self.assertEqual(813 len(breakpoint_ids), len(lines), "expect correct number of breakpoints"814 )815 self.continue_to_breakpoints(breakpoint_ids)816 817 # Verify locals value format decimal818 is_hex = False819 var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)820 self.assertEqual(var_pt_x["value"], "11")821 var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)822 self.assertEqual(var_pt_y["value"], "22")823 824 # Verify locals value format hexical825 is_hex = True826 var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)827 self.assertEqual(var_pt_x["value"], "0x0000000b")828 var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)829 self.assertEqual(var_pt_y["value"], "0x00000016")830 831 # Toggle and verify locals value format decimal again832 is_hex = False833 var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)834 self.assertEqual(var_pt_x["value"], "11")835 var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)836 self.assertEqual(var_pt_y["value"], "22")837