xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision b8d38bb56d59bee39872fee348a07f79c12f51ae)
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": "{x:11, y:22, buffer:{...}}"
258                    if enableAutoVariableSummaries
259                    else "PointType @ 0x"
260                },
261                "hasVariablesReference": True,
262            },
263            "pt.buffer": {
264                "equals": {"type": "int[16]"},
265                "startswith": {
266                    "result": "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
267                    if enableAutoVariableSummaries
268                    else "int[16] @ 0x"
269                },
270                "hasVariablesReference": True,
271            },
272            "argv": {
273                "equals": {"type": "const char **"},
274                "startswith": {"result": "0x"},
275                "hasVariablesReference": True,
276            },
277            "argv[0]": {
278                "equals": {"type": "const char *"},
279                "startswith": {"result": "0x"},
280                "hasVariablesReference": True,
281            },
282            "2+3": {
283                "equals": {"result": "5", "type": "int"},
284                "hasVariablesReference": False,
285            },
286        }
287        for expression in expressions:
288            response = self.dap_server.request_evaluate(expression)
289            self.verify_values(expressions[expression], response["body"])
290
291        # Test setting variables
292        self.set_local("argc", 123)
293        argc = self.get_local_as_int("argc")
294        self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % (argc))
295
296        self.set_local("argv", 0x1234)
297        argv = self.get_local_as_int("argv")
298        self.assertEqual(
299            argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % (argv)
300        )
301
302        # Set a variable value whose name is synthetic, like a variable index
303        # and verify the value by reading it
304        self.dap_server.request_setVariable(varRef, "[0]", 100)
305        response = self.dap_server.request_variables(varRef, start=0, count=1)
306        self.verify_variables(
307            make_buffer_verify_dict(0, 1, 100), response["body"]["variables"]
308        )
309
310        # Set a variable value whose name is a real child value, like "pt.x"
311        # and verify the value by reading it
312        varRef = varref_dict["pt"]
313        self.dap_server.request_setVariable(varRef, "x", 111)
314        response = self.dap_server.request_variables(varRef, start=0, count=1)
315        value = response["body"]["variables"][0]["value"]
316        self.assertEqual(
317            value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)
318        )
319
320        # We check shadowed variables and that a new get_local_variables request
321        # gets the right data
322        breakpoint2_line = line_number(source, "// breakpoint 2")
323        lines = [breakpoint2_line]
324        breakpoint_ids = self.set_source_breakpoints(source, lines)
325        self.assertEqual(
326            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
327        )
328        self.continue_to_breakpoints(breakpoint_ids)
329
330        verify_locals["argc"]["equals"]["value"] = "123"
331        verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
332        verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
333        verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
334        verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
335
336        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
337
338        # Now we verify that we correctly change the name of a variable with and without differentiator suffix
339        self.assertFalse(self.dap_server.request_setVariable(1, "x2", 9)["success"])
340        self.assertFalse(
341            self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"]
342        )
343
344        self.assertTrue(
345            self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
346        )
347        self.assertTrue(
348            self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
349        )
350        self.assertTrue(
351            self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
352        )
353
354        # The following should have no effect
355        self.assertFalse(
356            self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[
357                "success"
358            ]
359        )
360
361        verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
362        verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
363        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
364
365        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
366
367        # The plain x variable shold refer to the innermost x
368        self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"])
369        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
370
371        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
372
373        # In breakpoint 3, there should be no shadowed variables
374        breakpoint3_line = line_number(source, "// breakpoint 3")
375        lines = [breakpoint3_line]
376        breakpoint_ids = self.set_source_breakpoints(source, lines)
377        self.assertEqual(
378            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
379        )
380        self.continue_to_breakpoints(breakpoint_ids)
381
382        locals = self.dap_server.get_local_variables()
383        names = [var["name"] for var in locals]
384        # The first shadowed x shouldn't have a suffix anymore
385        verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
386        self.assertNotIn("x @ main.cpp:17", names)
387        self.assertNotIn("x @ main.cpp:19", names)
388        self.assertNotIn("x @ main.cpp:21", names)
389
390        self.verify_variables(verify_locals, locals)
391
392    @skipIfWindows
393    @skipIfRemote
394    def test_scopes_variables_setVariable_evaluate(self):
395        self.do_test_scopes_variables_setVariable_evaluate(
396            enableAutoVariableSummaries=False
397        )
398
399    @skipIfWindows
400    @skipIfRemote
401    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
402        self.do_test_scopes_variables_setVariable_evaluate(
403            enableAutoVariableSummaries=True
404        )
405
406    def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):
407        """
408        Tests the evaluated expression expands successfully after "scopes" packets
409        and permanent expressions persist.
410        """
411        program = self.getBuildArtifact("a.out")
412        self.build_and_launch(
413            program, enableAutoVariableSummaries=enableAutoVariableSummaries
414        )
415        source = "main.cpp"
416        breakpoint1_line = line_number(source, "// breakpoint 1")
417        lines = [breakpoint1_line]
418        # Set breakpoint in the thread function so we can step the threads
419        breakpoint_ids = self.set_source_breakpoints(source, lines)
420        self.assertEqual(
421            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
422        )
423        self.continue_to_breakpoints(breakpoint_ids)
424
425        # Verify locals
426        locals = self.dap_server.get_local_variables()
427        buffer_children = make_buffer_verify_dict(0, 32)
428        verify_locals = {
429            "argc": {
430                "equals": {"type": "int", "value": "1"},
431                "missing": ["indexedVariables"],
432            },
433            "argv": {
434                "equals": {"type": "const char **"},
435                "startswith": {"value": "0x"},
436                "hasVariablesReference": True,
437                "missing": ["indexedVariables"],
438            },
439            "pt": {
440                "equals": {"type": "PointType"},
441                "hasVariablesReference": True,
442                "missing": ["indexedVariables"],
443                "children": {
444                    "x": {
445                        "equals": {"type": "int", "value": "11"},
446                        "missing": ["indexedVariables"],
447                    },
448                    "y": {
449                        "equals": {"type": "int", "value": "22"},
450                        "missing": ["indexedVariables"],
451                    },
452                    "buffer": {
453                        "children": buffer_children,
454                        "equals": {"indexedVariables": 16},
455                    },
456                },
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 = 11
475  y = 22
476  buffer = {
477    [0] = 0
478    [1] = 1
479    [2] = 2
480    [3] = 3
481    [4] = 4
482    [5] = 5
483    [6] = 6
484    [7] = 7
485    [8] = 8
486    [9] = 9
487    [10] = 10
488    [11] = 11
489    [12] = 12
490    [13] = 13
491    [14] = 14
492    [15] = 15
493  }
494}"""
495                    },
496                    "missing": ["indexedVariables"],
497                    "hasVariablesReference": True,
498                },
499                "hover": {
500                    "equals": {"type": "PointType"},
501                    "equals": {
502                        "result": """(PointType) pt = {
503  x = 11
504  y = 22
505  buffer = {
506    [0] = 0
507    [1] = 1
508    [2] = 2
509    [3] = 3
510    [4] = 4
511    [5] = 5
512    [6] = 6
513    [7] = 7
514    [8] = 8
515    [9] = 9
516    [10] = 10
517    [11] = 11
518    [12] = 12
519    [13] = 13
520    [14] = 14
521    [15] = 15
522  }
523}"""
524                    },
525                    "missing": ["indexedVariables"],
526                    "hasVariablesReference": True,
527                },
528                "watch": {
529                    "equals": {"type": "PointType"},
530                    "startswith": {
531                        "result": "{x:11, y:22, buffer:{...}}"
532                        if enableAutoVariableSummaries
533                        else "PointType @ 0x"
534                    },
535                    "missing": ["indexedVariables"],
536                    "hasVariablesReference": True,
537                },
538                "variables": {
539                    "equals": {"type": "PointType"},
540                    "startswith": {
541                        "result": "{x:11, y:22, buffer:{...}}"
542                        if enableAutoVariableSummaries
543                        else "PointType @ 0x"
544                    },
545                    "missing": ["indexedVariables"],
546                    "hasVariablesReference": True,
547                },
548            },
549            "children": {
550                "x": {"equals": {"type": "int", "value": "11"}},
551                "y": {"equals": {"type": "int", "value": "22"}},
552                "buffer": {"children": buffer_children},
553            },
554        }
555
556        # Evaluate from known contexts.
557        expr_varref_dict = {}
558        for context, verify_dict in expandable_expression["context"].items():
559            response = self.dap_server.request_evaluate(
560                expandable_expression["name"],
561                frameIndex=0,
562                threadId=None,
563                context=context,
564            )
565            self.verify_values(
566                verify_dict,
567                response["body"],
568                expr_varref_dict,
569                expandable_expression["name"],
570            )
571
572        # Evaluate locals again.
573        locals = self.dap_server.get_local_variables()
574        self.verify_variables(verify_locals, locals)
575
576        # Verify the evaluated expressions before second locals evaluation
577        # can be expanded.
578        var_ref = expr_varref_dict[expandable_expression["name"]]
579        response = self.dap_server.request_variables(var_ref)
580        self.verify_variables(
581            expandable_expression["children"], response["body"]["variables"]
582        )
583
584        # Continue to breakpoint 3, permanent variable should still exist
585        # after resume.
586        breakpoint3_line = line_number(source, "// breakpoint 3")
587        lines = [breakpoint3_line]
588        breakpoint_ids = self.set_source_breakpoints(source, lines)
589        self.assertEqual(
590            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
591        )
592        self.continue_to_breakpoints(breakpoint_ids)
593
594        var_ref = expr_varref_dict[expandable_expression["name"]]
595        response = self.dap_server.request_variables(var_ref)
596        self.verify_variables(
597            expandable_expression["children"], response["body"]["variables"]
598        )
599
600        # Test that frame scopes have corresponding presentation hints.
601        frame_id = self.dap_server.get_stackFrame()["id"]
602        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
603
604        scope_names = [scope["name"] for scope in scopes]
605        self.assertIn("Locals", scope_names)
606        self.assertIn("Registers", scope_names)
607
608        for scope in scopes:
609            if scope["name"] == "Locals":
610                self.assertEqual(scope.get("presentationHint"), "locals")
611            if scope["name"] == "Registers":
612                self.assertEqual(scope.get("presentationHint"), "registers")
613
614    @skipIfWindows
615    @skipIfRemote
616    def test_scopes_and_evaluate_expansion(self):
617        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
618
619    @skipIfWindows
620    @skipIfRemote
621    def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
622        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
623
624    def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
625        """
626        Tests that arrays and lldb.SBValue objects that have synthetic child
627        providers have "indexedVariables" key/value pairs. This helps the IDE
628        not to fetch too many children all at once.
629        """
630        program = self.getBuildArtifact("a.out")
631        self.build_and_launch(
632            program, enableSyntheticChildDebugging=enableSyntheticChildDebugging
633        )
634        source = "main.cpp"
635        breakpoint1_line = line_number(source, "// breakpoint 4")
636        lines = [breakpoint1_line]
637        # Set breakpoint in the thread function so we can step the threads
638        breakpoint_ids = self.set_source_breakpoints(source, lines)
639        self.assertEqual(
640            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
641        )
642        self.continue_to_breakpoints(breakpoint_ids)
643
644        # Verify locals
645        locals = self.dap_server.get_local_variables()
646        # The vector variables might have one additional entry from the fake
647        # "[raw]" child.
648        raw_child_count = 1 if enableSyntheticChildDebugging else 0
649        verify_locals = {
650            "small_array": {"equals": {"indexedVariables": 5}},
651            "large_array": {"equals": {"indexedVariables": 200}},
652            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
653            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
654            "pt": {"missing": ["indexedVariables"]},
655        }
656        self.verify_variables(verify_locals, locals)
657
658        # We also verify that we produce a "[raw]" fake child with the real
659        # SBValue for the synthetic type.
660        verify_children = {
661            "[0]": {"equals": {"type": "int", "value": "0"}},
662            "[1]": {"equals": {"type": "int", "value": "0"}},
663            "[2]": {"equals": {"type": "int", "value": "0"}},
664            "[3]": {"equals": {"type": "int", "value": "0"}},
665            "[4]": {"equals": {"type": "int", "value": "0"}},
666        }
667        if enableSyntheticChildDebugging:
668            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
669
670        children = self.dap_server.request_variables(locals[2]["variablesReference"])[
671            "body"
672        ]["variables"]
673        self.verify_variables(verify_children, children)
674
675    @skipIfWindows
676    @skipIfRemote
677    def test_indexedVariables(self):
678        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
679
680    @skipIfWindows
681    @skipIfRemote
682    def test_indexedVariables_with_raw_child_for_synthetics(self):
683        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
684
685    @skipIfWindows
686    @skipIfRemote
687    def test_registers(self):
688        """
689        Test that registers whose byte size is the size of a pointer on
690        the current system get formatted as lldb::eFormatAddressInfo. This
691        will show the pointer value followed by a description of the address
692        itself. To test this we attempt to find the PC value in the general
693        purpose registers, and since we will be stopped in main.cpp, verify
694        that the value for the PC starts with a pointer and is followed by
695        a description that contains main.cpp.
696        """
697        program = self.getBuildArtifact("a.out")
698        self.build_and_launch(program)
699        source = "main.cpp"
700        breakpoint1_line = line_number(source, "// breakpoint 1")
701        lines = [breakpoint1_line]
702        # Set breakpoint in the thread function so we can step the threads
703        breakpoint_ids = self.set_source_breakpoints(source, lines)
704        self.assertEqual(
705            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
706        )
707        self.continue_to_breakpoints(breakpoint_ids)
708
709        pc_name = None
710        arch = self.getArchitecture()
711        if arch == "x86_64":
712            pc_name = "rip"
713        elif arch == "x86":
714            pc_name = "rip"
715        elif arch.startswith("arm"):
716            pc_name = "pc"
717
718        if pc_name is None:
719            return
720        # Verify locals
721        reg_sets = self.dap_server.get_registers()
722        for reg_set in reg_sets:
723            if reg_set["name"] == "General Purpose Registers":
724                varRef = reg_set["variablesReference"]
725                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
726                for reg in regs:
727                    if reg["name"] == pc_name:
728                        value = reg["value"]
729                        self.assertTrue(value.startswith("0x"))
730                        self.assertIn("a.out`main + ", value)
731                        self.assertIn("at main.cpp:", value)
732
733    @no_debug_info_test
734    @skipUnlessDarwin
735    def test_darwin_dwarf_missing_obj(self):
736        """
737        Test that if we build a binary with DWARF in .o files and we remove
738        the .o file for main.cpp, that we get a variable named "<error>"
739        whose value matches the appriopriate error. Errors when getting
740        variables are returned in the LLDB API when the user should be
741        notified of issues that can easily be solved by rebuilding or
742        changing compiler options and are designed to give better feedback
743        to the user.
744        """
745        self.darwin_dwarf_missing_obj(None)
746
747    @no_debug_info_test
748    @skipUnlessDarwin
749    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
750        """
751        Test that if we build a binary with DWARF in .o files and we remove
752        the .o file for main.cpp, that we get a variable named "<error>"
753        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
754        """
755        initCommands = ["settings set symbols.load-on-demand true"]
756        self.darwin_dwarf_missing_obj(initCommands)
757
758    @no_debug_info_test
759    @skipIfWindows
760    @skipIfRemote
761    def test_value_format(self):
762        """
763        Test that toggle variables value format between decimal and hexical works.
764        """
765        program = self.getBuildArtifact("a.out")
766        self.build_and_launch(program)
767        source = "main.cpp"
768        breakpoint1_line = line_number(source, "// breakpoint 1")
769        lines = [breakpoint1_line]
770
771        breakpoint_ids = self.set_source_breakpoints(source, lines)
772        self.assertEqual(
773            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
774        )
775        self.continue_to_breakpoints(breakpoint_ids)
776
777        # Verify locals value format decimal
778        is_hex = False
779        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
780        self.assertEquals(var_pt_x["value"], "11")
781        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
782        self.assertEquals(var_pt_y["value"], "22")
783
784        # Verify locals value format hexical
785        is_hex = True
786        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
787        self.assertEquals(var_pt_x["value"], "0x0000000b")
788        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
789        self.assertEquals(var_pt_y["value"], "0x00000016")
790
791        # Toggle and verify locals value format decimal again
792        is_hex = False
793        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
794        self.assertEquals(var_pt_x["value"], "11")
795        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
796        self.assertEquals(var_pt_y["value"], "22")
797