xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision a4ad05284e97dd188c44252846486cbfb74a884c)
1"""
2Test lldb-dap setBreakpoints request
3"""
4
5import os
6
7import dap_server
8import lldbdap_testcase
9from lldbsuite.test import lldbutil
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12
13
14def make_buffer_verify_dict(start_idx, count, offset=0):
15    verify_dict = {}
16    for i in range(start_idx, start_idx + count):
17        verify_dict["[%i]" % (i)] = {"type": "int", "value": str(i + offset)}
18    return verify_dict
19
20
21class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
22    def verify_values(self, verify_dict, actual, varref_dict=None, expression=None):
23        if "equals" in verify_dict:
24            verify = verify_dict["equals"]
25            for key in verify:
26                verify_value = verify[key]
27                actual_value = actual[key]
28                self.assertEqual(
29                    verify_value,
30                    actual_value,
31                    '"%s" keys don\'t match (%s != %s) from:\n%s'
32                    % (key, actual_value, verify_value, actual),
33                )
34        if "startswith" in verify_dict:
35            verify = verify_dict["startswith"]
36            for key in verify:
37                verify_value = verify[key]
38                actual_value = actual[key]
39                startswith = actual_value.startswith(verify_value)
40                self.assertTrue(
41                    startswith,
42                    ('"%s" value "%s" doesn\'t start with "%s")')
43                    % (key, actual_value, verify_value),
44                )
45        if "matches" in verify_dict:
46            verify = verify_dict["matches"]
47            for key in verify:
48                verify_value = verify[key]
49                actual_value = actual[key]
50                self.assertRegex(
51                    actual_value,
52                    verify_value,
53                    ('"%s" value "%s" doesn\'t match pattern "%s")')
54                    % (key, actual_value, verify_value),
55                )
56        if "contains" in verify_dict:
57            verify = verify_dict["contains"]
58            for key in verify:
59                contains_array = verify[key]
60                actual_value = actual[key]
61                self.assertIsInstance(contains_array, list)
62                for verify_value in contains_array:
63                    self.assertIn(verify_value, actual_value)
64        if "missing" in verify_dict:
65            missing = verify_dict["missing"]
66            for key in missing:
67                self.assertNotIn(
68                    key, actual, 'key "%s" is not expected in %s' % (key, actual)
69                )
70        hasVariablesReference = "variablesReference" in actual
71        varRef = None
72        if hasVariablesReference:
73            # Remember variable references in case we want to test further
74            # by using the evaluate name.
75            varRef = actual["variablesReference"]
76            if varRef != 0 and varref_dict is not None:
77                if expression is None:
78                    evaluateName = actual["evaluateName"]
79                else:
80                    evaluateName = expression
81                varref_dict[evaluateName] = varRef
82        if (
83            "hasVariablesReference" in verify_dict
84            and verify_dict["hasVariablesReference"]
85        ):
86            self.assertTrue(hasVariablesReference, "verify variable reference")
87        if "children" in verify_dict:
88            self.assertTrue(
89                hasVariablesReference and varRef is not None and varRef != 0,
90                ("children verify values specified for " "variable without children"),
91            )
92
93            response = self.dap_server.request_variables(varRef)
94            self.verify_variables(
95                verify_dict["children"], response["body"]["variables"], varref_dict
96            )
97
98    def verify_variables(self, verify_dict, variables, varref_dict=None):
99        for variable in variables:
100            name = variable["name"]
101            if not name.startswith("std::"):
102                self.assertIn(
103                    name, verify_dict, 'variable "%s" in verify dictionary' % (name)
104                )
105                self.verify_values(verify_dict[name], variable, varref_dict)
106
107    def darwin_dwarf_missing_obj(self, initCommands):
108        self.build(debug_info="dwarf")
109        program = self.getBuildArtifact("a.out")
110        main_obj = self.getBuildArtifact("main.o")
111        self.assertTrue(os.path.exists(main_obj))
112        # Delete the main.o file that contains the debug info so we force an
113        # error when we run to main and try to get variables
114        os.unlink(main_obj)
115
116        self.create_debug_adaptor()
117        self.assertTrue(os.path.exists(program), "executable must exist")
118
119        self.launch(program=program, initCommands=initCommands)
120
121        functions = ["main"]
122        breakpoint_ids = self.set_function_breakpoints(functions)
123        self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")
124        self.continue_to_breakpoints(breakpoint_ids)
125
126        locals = self.dap_server.get_local_variables()
127
128        verify_locals = {
129            "<error>": {
130                "equals": {"type": "const char *"},
131                "contains": {
132                    "value": [
133                        "debug map object file ",
134                        'main.o" containing debug info does not exist, debug info will not be loaded',
135                    ]
136                },
137            },
138        }
139        varref_dict = {}
140        self.verify_variables(verify_locals, locals, varref_dict)
141
142    def do_test_scopes_variables_setVariable_evaluate(
143        self, enableAutoVariableSummaries: bool
144    ):
145        """
146        Tests the "scopes", "variables", "setVariable", and "evaluate"
147        packets.
148        """
149        program = self.getBuildArtifact("a.out")
150        self.build_and_launch(
151            program, enableAutoVariableSummaries=enableAutoVariableSummaries
152        )
153        source = "main.cpp"
154        breakpoint1_line = line_number(source, "// breakpoint 1")
155        lines = [breakpoint1_line]
156        # Set breakpoint in the thread function so we can step the threads
157        breakpoint_ids = self.set_source_breakpoints(source, lines)
158        self.assertEqual(
159            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
160        )
161        self.continue_to_breakpoints(breakpoint_ids)
162        locals = self.dap_server.get_local_variables()
163        globals = self.dap_server.get_global_variables()
164        buffer_children = make_buffer_verify_dict(0, 16)
165        verify_locals = {
166            "argc": {
167                "equals": {
168                    "type": "int",
169                    "value": "1",
170                },
171                "$__lldb_extensions": {
172                    "equals": {
173                        "value": "1",
174                    },
175                    "declaration": {
176                        "equals": {"line": 12, "column": 14},
177                        "contains": {"path": ["lldb-dap", "variables", "main.cpp"]},
178                    },
179                },
180            },
181            "argv": {
182                "equals": {"type": "const char **"},
183                "startswith": {"value": "0x"},
184                "hasVariablesReference": True,
185            },
186            "pt": {
187                "equals": {
188                    "type": "PointType",
189                },
190                "hasVariablesReference": True,
191                "children": {
192                    "x": {"equals": {"type": "int", "value": "11"}},
193                    "y": {"equals": {"type": "int", "value": "22"}},
194                    "buffer": {"children": buffer_children},
195                },
196            },
197            "x": {"equals": {"type": "int"}},
198        }
199        if enableAutoVariableSummaries:
200            verify_locals["pt"]["$__lldb_extensions"] = {
201                "equals": {"autoSummary": "{x:11, y:22}"}
202            }
203        verify_globals = {
204            "s_local": {"equals": {"type": "float", "value": "2.25"}},
205            "::g_global": {"equals": {"type": "int", "value": "123"}},
206            "s_global": {"equals": {"type": "int", "value": "234"}},
207        }
208        varref_dict = {}
209        self.verify_variables(verify_locals, locals, varref_dict)
210        self.verify_variables(verify_globals, globals, varref_dict)
211        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
212        # We need to test the functionality of the "variables" request as it
213        # has optional parameters like "start" and "count" to limit the number
214        # of variables that are fetched
215        varRef = varref_dict["pt.buffer"]
216        response = self.dap_server.request_variables(varRef)
217        self.verify_variables(buffer_children, response["body"]["variables"])
218        # Verify setting start=0 in the arguments still gets all children
219        response = self.dap_server.request_variables(varRef, start=0)
220        self.verify_variables(buffer_children, response["body"]["variables"])
221        # Verify setting count=0 in the arguments still gets all children.
222        # If count is zero, it means to get all children.
223        response = self.dap_server.request_variables(varRef, count=0)
224        self.verify_variables(buffer_children, response["body"]["variables"])
225        # Verify setting count to a value that is too large in the arguments
226        # still gets all children, and no more
227        response = self.dap_server.request_variables(varRef, count=1000)
228        self.verify_variables(buffer_children, response["body"]["variables"])
229        # Verify setting the start index and count gets only the children we
230        # want
231        response = self.dap_server.request_variables(varRef, start=5, count=5)
232        self.verify_variables(
233            make_buffer_verify_dict(5, 5), response["body"]["variables"]
234        )
235        # Verify setting the start index to a value that is out of range
236        # results in an empty list
237        response = self.dap_server.request_variables(varRef, start=32, count=1)
238        self.assertEqual(
239            len(response["body"]["variables"]),
240            0,
241            "verify we get no variable back for invalid start",
242        )
243
244        # Test evaluate
245        expressions = {
246            "pt.x": {
247                "equals": {"result": "11", "type": "int"},
248                "hasVariablesReference": False,
249            },
250            "pt.buffer[2]": {
251                "equals": {"result": "2", "type": "int"},
252                "hasVariablesReference": False,
253            },
254            "pt": {
255                "equals": {"type": "PointType"},
256                "startswith": {
257                    "result": (
258                        "{x:11, y:22, buffer:{...}}"
259                        if enableAutoVariableSummaries
260                        else "PointType @ 0x"
261                    )
262                },
263                "hasVariablesReference": True,
264            },
265            "pt.buffer": {
266                "equals": {"type": "int[16]"},
267                "startswith": {
268                    "result": (
269                        "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
270                        if enableAutoVariableSummaries
271                        else "int[16] @ 0x"
272                    )
273                },
274                "hasVariablesReference": True,
275            },
276            "argv": {
277                "equals": {"type": "const char **"},
278                "startswith": {"result": "0x"},
279                "hasVariablesReference": True,
280            },
281            "argv[0]": {
282                "equals": {"type": "const char *"},
283                "startswith": {"result": "0x"},
284                "hasVariablesReference": True,
285            },
286            "2+3": {
287                "equals": {"result": "5", "type": "int"},
288                "hasVariablesReference": False,
289            },
290        }
291        for expression in expressions:
292            response = self.dap_server.request_evaluate(expression)
293            self.verify_values(expressions[expression], response["body"])
294
295        # Test setting variables
296        self.set_local("argc", 123)
297        argc = self.get_local_as_int("argc")
298        self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % (argc))
299
300        self.set_local("argv", 0x1234)
301        argv = self.get_local_as_int("argv")
302        self.assertEqual(
303            argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % (argv)
304        )
305
306        # Set a variable value whose name is synthetic, like a variable index
307        # and verify the value by reading it
308        self.dap_server.request_setVariable(varRef, "[0]", 100)
309        response = self.dap_server.request_variables(varRef, start=0, count=1)
310        self.verify_variables(
311            make_buffer_verify_dict(0, 1, 100), response["body"]["variables"]
312        )
313
314        # Set a variable value whose name is a real child value, like "pt.x"
315        # and verify the value by reading it
316        varRef = varref_dict["pt"]
317        self.dap_server.request_setVariable(varRef, "x", 111)
318        response = self.dap_server.request_variables(varRef, start=0, count=1)
319        value = response["body"]["variables"][0]["value"]
320        self.assertEqual(
321            value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)
322        )
323
324        # We check shadowed variables and that a new get_local_variables request
325        # gets the right data
326        breakpoint2_line = line_number(source, "// breakpoint 2")
327        lines = [breakpoint2_line]
328        breakpoint_ids = self.set_source_breakpoints(source, lines)
329        self.assertEqual(
330            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
331        )
332        self.continue_to_breakpoints(breakpoint_ids)
333
334        verify_locals["argc"]["equals"]["value"] = "123"
335        verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
336        verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
337        verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
338        verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
339
340        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
341
342        # Now we verify that we correctly change the name of a variable with and without differentiator suffix
343        self.assertFalse(self.dap_server.request_setVariable(1, "x2", 9)["success"])
344        self.assertFalse(
345            self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"]
346        )
347
348        self.assertTrue(
349            self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
350        )
351        self.assertTrue(
352            self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
353        )
354        self.assertTrue(
355            self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
356        )
357
358        # The following should have no effect
359        self.assertFalse(
360            self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[
361                "success"
362            ]
363        )
364
365        verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
366        verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
367        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
368
369        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
370
371        # The plain x variable shold refer to the innermost x
372        self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"])
373        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
374
375        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
376
377        # In breakpoint 3, there should be no shadowed variables
378        breakpoint3_line = line_number(source, "// breakpoint 3")
379        lines = [breakpoint3_line]
380        breakpoint_ids = self.set_source_breakpoints(source, lines)
381        self.assertEqual(
382            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
383        )
384        self.continue_to_breakpoints(breakpoint_ids)
385
386        locals = self.dap_server.get_local_variables()
387        names = [var["name"] for var in locals]
388        # The first shadowed x shouldn't have a suffix anymore
389        verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
390        self.assertNotIn("x @ main.cpp:17", names)
391        self.assertNotIn("x @ main.cpp:19", names)
392        self.assertNotIn("x @ main.cpp:21", names)
393
394        self.verify_variables(verify_locals, locals)
395
396    @skipIfWindows
397    @skipIfRemote
398    def test_scopes_variables_setVariable_evaluate(self):
399        self.do_test_scopes_variables_setVariable_evaluate(
400            enableAutoVariableSummaries=False
401        )
402
403    @skipIfWindows
404    @skipIfRemote
405    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
406        self.do_test_scopes_variables_setVariable_evaluate(
407            enableAutoVariableSummaries=True
408        )
409
410    def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):
411        """
412        Tests the evaluated expression expands successfully after "scopes" packets
413        and permanent expressions persist.
414        """
415        program = self.getBuildArtifact("a.out")
416        self.build_and_launch(
417            program, enableAutoVariableSummaries=enableAutoVariableSummaries
418        )
419        source = "main.cpp"
420        breakpoint1_line = line_number(source, "// breakpoint 1")
421        lines = [breakpoint1_line]
422        # Set breakpoint in the thread function so we can step the threads
423        breakpoint_ids = self.set_source_breakpoints(source, lines)
424        self.assertEqual(
425            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
426        )
427        self.continue_to_breakpoints(breakpoint_ids)
428
429        # Verify locals
430        locals = self.dap_server.get_local_variables()
431        buffer_children = make_buffer_verify_dict(0, 32)
432        verify_locals = {
433            "argc": {
434                "equals": {"type": "int", "value": "1"},
435                "missing": ["indexedVariables"],
436            },
437            "argv": {
438                "equals": {"type": "const char **"},
439                "startswith": {"value": "0x"},
440                "hasVariablesReference": True,
441                "missing": ["indexedVariables"],
442            },
443            "pt": {
444                "equals": {"type": "PointType"},
445                "hasVariablesReference": True,
446                "missing": ["indexedVariables"],
447                "children": {
448                    "x": {
449                        "equals": {"type": "int", "value": "11"},
450                        "missing": ["indexedVariables"],
451                    },
452                    "y": {
453                        "equals": {"type": "int", "value": "22"},
454                        "missing": ["indexedVariables"],
455                    },
456                    "buffer": {
457                        "children": buffer_children,
458                        "equals": {"indexedVariables": 16},
459                    },
460                },
461            },
462            "x": {
463                "equals": {"type": "int"},
464                "missing": ["indexedVariables"],
465            },
466        }
467        self.verify_variables(verify_locals, locals)
468
469        # Evaluate expandable expression twice: once permanent (from repl)
470        # the other temporary (from other UI).
471        expandable_expression = {
472            "name": "pt",
473            "context": {
474                "repl": {
475                    "equals": {"type": "PointType"},
476                    "equals": {
477                        "result": """(PointType) $0 = {
478  x = 11
479  y = 22
480  buffer = {
481    [0] = 0
482    [1] = 1
483    [2] = 2
484    [3] = 3
485    [4] = 4
486    [5] = 5
487    [6] = 6
488    [7] = 7
489    [8] = 8
490    [9] = 9
491    [10] = 10
492    [11] = 11
493    [12] = 12
494    [13] = 13
495    [14] = 14
496    [15] = 15
497  }
498}"""
499                    },
500                    "missing": ["indexedVariables"],
501                    "hasVariablesReference": True,
502                },
503                "hover": {
504                    "equals": {"type": "PointType"},
505                    "equals": {
506                        "result": """(PointType) pt = {
507  x = 11
508  y = 22
509  buffer = {
510    [0] = 0
511    [1] = 1
512    [2] = 2
513    [3] = 3
514    [4] = 4
515    [5] = 5
516    [6] = 6
517    [7] = 7
518    [8] = 8
519    [9] = 9
520    [10] = 10
521    [11] = 11
522    [12] = 12
523    [13] = 13
524    [14] = 14
525    [15] = 15
526  }
527}"""
528                    },
529                    "missing": ["indexedVariables"],
530                    "hasVariablesReference": True,
531                },
532                "watch": {
533                    "equals": {"type": "PointType"},
534                    "startswith": {
535                        "result": (
536                            "{x:11, y:22, buffer:{...}}"
537                            if enableAutoVariableSummaries
538                            else "PointType @ 0x"
539                        )
540                    },
541                    "missing": ["indexedVariables"],
542                    "hasVariablesReference": True,
543                },
544                "variables": {
545                    "equals": {"type": "PointType"},
546                    "startswith": {
547                        "result": (
548                            "{x:11, y:22, buffer:{...}}"
549                            if enableAutoVariableSummaries
550                            else "PointType @ 0x"
551                        )
552                    },
553                    "missing": ["indexedVariables"],
554                    "hasVariablesReference": True,
555                },
556            },
557            "children": {
558                "x": {"equals": {"type": "int", "value": "11"}},
559                "y": {"equals": {"type": "int", "value": "22"}},
560                "buffer": {"children": buffer_children},
561            },
562        }
563
564        # Evaluate from known contexts.
565        expr_varref_dict = {}
566        for context, verify_dict in expandable_expression["context"].items():
567            response = self.dap_server.request_evaluate(
568                expandable_expression["name"],
569                frameIndex=0,
570                threadId=None,
571                context=context,
572            )
573            self.verify_values(
574                verify_dict,
575                response["body"],
576                expr_varref_dict,
577                expandable_expression["name"],
578            )
579
580        # Evaluate locals again.
581        locals = self.dap_server.get_local_variables()
582        self.verify_variables(verify_locals, locals)
583
584        # Verify the evaluated expressions before second locals evaluation
585        # can be expanded.
586        var_ref = expr_varref_dict[expandable_expression["name"]]
587        response = self.dap_server.request_variables(var_ref)
588        self.verify_variables(
589            expandable_expression["children"], response["body"]["variables"]
590        )
591
592        # Continue to breakpoint 3, permanent variable should still exist
593        # after resume.
594        breakpoint3_line = line_number(source, "// breakpoint 3")
595        lines = [breakpoint3_line]
596        breakpoint_ids = self.set_source_breakpoints(source, lines)
597        self.assertEqual(
598            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
599        )
600        self.continue_to_breakpoints(breakpoint_ids)
601
602        var_ref = expr_varref_dict[expandable_expression["name"]]
603        response = self.dap_server.request_variables(var_ref)
604        self.verify_variables(
605            expandable_expression["children"], response["body"]["variables"]
606        )
607
608        # Test that frame scopes have corresponding presentation hints.
609        frame_id = self.dap_server.get_stackFrame()["id"]
610        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
611
612        scope_names = [scope["name"] for scope in scopes]
613        self.assertIn("Locals", scope_names)
614        self.assertIn("Registers", scope_names)
615
616        for scope in scopes:
617            if scope["name"] == "Locals":
618                self.assertEqual(scope.get("presentationHint"), "locals")
619            if scope["name"] == "Registers":
620                self.assertEqual(scope.get("presentationHint"), "registers")
621
622    @skipIfWindows
623    @skipIfRemote
624    def test_scopes_and_evaluate_expansion(self):
625        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
626
627    @skipIfWindows
628    @skipIfRemote
629    def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
630        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
631
632    def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
633        """
634        Tests that arrays and lldb.SBValue objects that have synthetic child
635        providers have "indexedVariables" key/value pairs. This helps the IDE
636        not to fetch too many children all at once.
637        """
638        program = self.getBuildArtifact("a.out")
639        self.build_and_launch(
640            program, enableSyntheticChildDebugging=enableSyntheticChildDebugging
641        )
642        source = "main.cpp"
643        breakpoint1_line = line_number(source, "// breakpoint 4")
644        lines = [breakpoint1_line]
645        # Set breakpoint in the thread function so we can step the threads
646        breakpoint_ids = self.set_source_breakpoints(source, lines)
647        self.assertEqual(
648            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
649        )
650        self.continue_to_breakpoints(breakpoint_ids)
651
652        # Verify locals
653        locals = self.dap_server.get_local_variables()
654        # The vector variables might have one additional entry from the fake
655        # "[raw]" child.
656        raw_child_count = 1 if enableSyntheticChildDebugging else 0
657        verify_locals = {
658            "small_array": {"equals": {"indexedVariables": 5}},
659            "large_array": {"equals": {"indexedVariables": 200}},
660            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
661            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
662            "pt": {"missing": ["indexedVariables"]},
663        }
664        self.verify_variables(verify_locals, locals)
665
666        # We also verify that we produce a "[raw]" fake child with the real
667        # SBValue for the synthetic type.
668        verify_children = {
669            "[0]": {"equals": {"type": "int", "value": "0"}},
670            "[1]": {"equals": {"type": "int", "value": "0"}},
671            "[2]": {"equals": {"type": "int", "value": "0"}},
672            "[3]": {"equals": {"type": "int", "value": "0"}},
673            "[4]": {"equals": {"type": "int", "value": "0"}},
674        }
675        if enableSyntheticChildDebugging:
676            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
677
678        children = self.dap_server.request_variables(locals[2]["variablesReference"])[
679            "body"
680        ]["variables"]
681        self.verify_variables(verify_children, children)
682
683    @skipIfWindows
684    @skipIfRemote
685    def test_indexedVariables(self):
686        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
687
688    @skipIfWindows
689    @skipIfRemote
690    def test_indexedVariables_with_raw_child_for_synthetics(self):
691        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
692
693    @skipIfWindows
694    @skipIfRemote
695    def test_registers(self):
696        """
697        Test that registers whose byte size is the size of a pointer on
698        the current system get formatted as lldb::eFormatAddressInfo. This
699        will show the pointer value followed by a description of the address
700        itself. To test this we attempt to find the PC value in the general
701        purpose registers, and since we will be stopped in main.cpp, verify
702        that the value for the PC starts with a pointer and is followed by
703        a description that contains main.cpp.
704        """
705        program = self.getBuildArtifact("a.out")
706        self.build_and_launch(program)
707        source = "main.cpp"
708        breakpoint1_line = line_number(source, "// breakpoint 1")
709        lines = [breakpoint1_line]
710        # Set breakpoint in the thread function so we can step the threads
711        breakpoint_ids = self.set_source_breakpoints(source, lines)
712        self.assertEqual(
713            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
714        )
715        self.continue_to_breakpoints(breakpoint_ids)
716
717        pc_name = None
718        arch = self.getArchitecture()
719        if arch == "x86_64":
720            pc_name = "rip"
721        elif arch == "x86":
722            pc_name = "rip"
723        elif arch.startswith("arm"):
724            pc_name = "pc"
725
726        if pc_name is None:
727            return
728        # Verify locals
729        reg_sets = self.dap_server.get_registers()
730        for reg_set in reg_sets:
731            if reg_set["name"] == "General Purpose Registers":
732                varRef = reg_set["variablesReference"]
733                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
734                for reg in regs:
735                    if reg["name"] == pc_name:
736                        value = reg["value"]
737                        self.assertTrue(value.startswith("0x"))
738                        self.assertIn("a.out`main + ", value)
739                        self.assertIn("at main.cpp:", value)
740
741    @no_debug_info_test
742    @skipUnlessDarwin
743    def test_darwin_dwarf_missing_obj(self):
744        """
745        Test that if we build a binary with DWARF in .o files and we remove
746        the .o file for main.cpp, that we get a variable named "<error>"
747        whose value matches the appriopriate error. Errors when getting
748        variables are returned in the LLDB API when the user should be
749        notified of issues that can easily be solved by rebuilding or
750        changing compiler options and are designed to give better feedback
751        to the user.
752        """
753        self.darwin_dwarf_missing_obj(None)
754
755    @no_debug_info_test
756    @skipUnlessDarwin
757    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
758        """
759        Test that if we build a binary with DWARF in .o files and we remove
760        the .o file for main.cpp, that we get a variable named "<error>"
761        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
762        """
763        initCommands = ["settings set symbols.load-on-demand true"]
764        self.darwin_dwarf_missing_obj(initCommands)
765
766    @no_debug_info_test
767    @skipIfWindows
768    @skipIfRemote
769    def test_value_format(self):
770        """
771        Test that toggle variables value format between decimal and hexical works.
772        """
773        program = self.getBuildArtifact("a.out")
774        self.build_and_launch(program)
775        source = "main.cpp"
776        breakpoint1_line = line_number(source, "// breakpoint 1")
777        lines = [breakpoint1_line]
778
779        breakpoint_ids = self.set_source_breakpoints(source, lines)
780        self.assertEqual(
781            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
782        )
783        self.continue_to_breakpoints(breakpoint_ids)
784
785        # Verify locals value format decimal
786        is_hex = False
787        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
788        self.assertEqual(var_pt_x["value"], "11")
789        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
790        self.assertEqual(var_pt_y["value"], "22")
791
792        # Verify locals value format hexical
793        is_hex = True
794        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
795        self.assertEqual(var_pt_x["value"], "0x0000000b")
796        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
797        self.assertEqual(var_pt_y["value"], "0x00000016")
798
799        # Toggle and verify locals value format decimal again
800        is_hex = False
801        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
802        self.assertEqual(var_pt_x["value"], "11")
803        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
804        self.assertEqual(var_pt_y["value"], "22")
805