xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision af8f1554b8e7844304ce61b49b06e5b7946e9c47)
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                    "startswith": {
506                        "result": (
507                            "{x:11, y:22, buffer:{...}}"
508                            if enableAutoVariableSummaries
509                            else "PointType @ 0x"
510                        )
511                    },
512                    "missing": ["indexedVariables"],
513                    "hasVariablesReference": True,
514                },
515                "watch": {
516                    "equals": {"type": "PointType"},
517                    "startswith": {
518                        "result": (
519                            "{x:11, y:22, buffer:{...}}"
520                            if enableAutoVariableSummaries
521                            else "PointType @ 0x"
522                        )
523                    },
524                    "missing": ["indexedVariables"],
525                    "hasVariablesReference": True,
526                },
527                "variables": {
528                    "equals": {"type": "PointType"},
529                    "startswith": {
530                        "result": (
531                            "{x:11, y:22, buffer:{...}}"
532                            if enableAutoVariableSummaries
533                            else "PointType @ 0x"
534                        )
535                    },
536                    "missing": ["indexedVariables"],
537                    "hasVariablesReference": True,
538                },
539            },
540            "children": {
541                "x": {"equals": {"type": "int", "value": "11"}},
542                "y": {"equals": {"type": "int", "value": "22"}},
543                "buffer": {"children": buffer_children},
544            },
545        }
546
547        # Evaluate from known contexts.
548        expr_varref_dict = {}
549        for context, verify_dict in expandable_expression["context"].items():
550            response = self.dap_server.request_evaluate(
551                expandable_expression["name"],
552                frameIndex=0,
553                threadId=None,
554                context=context,
555            )
556            self.verify_values(
557                verify_dict,
558                response["body"],
559                expr_varref_dict,
560                expandable_expression["name"],
561            )
562
563        # Evaluate locals again.
564        locals = self.dap_server.get_local_variables()
565        self.verify_variables(verify_locals, locals)
566
567        # Verify the evaluated expressions before second locals evaluation
568        # can be expanded.
569        var_ref = expr_varref_dict[expandable_expression["name"]]
570        response = self.dap_server.request_variables(var_ref)
571        self.verify_variables(
572            expandable_expression["children"], response["body"]["variables"]
573        )
574
575        # Continue to breakpoint 3, permanent variable should still exist
576        # after resume.
577        breakpoint3_line = line_number(source, "// breakpoint 3")
578        lines = [breakpoint3_line]
579        breakpoint_ids = self.set_source_breakpoints(source, lines)
580        self.assertEqual(
581            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
582        )
583        self.continue_to_breakpoints(breakpoint_ids)
584
585        var_ref = expr_varref_dict[expandable_expression["name"]]
586        response = self.dap_server.request_variables(var_ref)
587        self.verify_variables(
588            expandable_expression["children"], response["body"]["variables"]
589        )
590
591        # Test that frame scopes have corresponding presentation hints.
592        frame_id = self.dap_server.get_stackFrame()["id"]
593        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
594
595        scope_names = [scope["name"] for scope in scopes]
596        self.assertIn("Locals", scope_names)
597        self.assertIn("Registers", scope_names)
598
599        for scope in scopes:
600            if scope["name"] == "Locals":
601                self.assertEqual(scope.get("presentationHint"), "locals")
602            if scope["name"] == "Registers":
603                self.assertEqual(scope.get("presentationHint"), "registers")
604
605    @skipIfWindows
606    @skipIfRemote
607    def test_scopes_and_evaluate_expansion(self):
608        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
609
610    @skipIfWindows
611    @skipIfRemote
612    def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
613        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
614
615    def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
616        """
617        Tests that arrays and lldb.SBValue objects that have synthetic child
618        providers have "indexedVariables" key/value pairs. This helps the IDE
619        not to fetch too many children all at once.
620        """
621        program = self.getBuildArtifact("a.out")
622        self.build_and_launch(
623            program, enableSyntheticChildDebugging=enableSyntheticChildDebugging
624        )
625        source = "main.cpp"
626        breakpoint1_line = line_number(source, "// breakpoint 4")
627        lines = [breakpoint1_line]
628        # Set breakpoint in the thread function so we can step the threads
629        breakpoint_ids = self.set_source_breakpoints(source, lines)
630        self.assertEqual(
631            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
632        )
633        self.continue_to_breakpoints(breakpoint_ids)
634
635        # Verify locals
636        locals = self.dap_server.get_local_variables()
637        # The vector variables might have one additional entry from the fake
638        # "[raw]" child.
639        raw_child_count = 1 if enableSyntheticChildDebugging else 0
640        verify_locals = {
641            "small_array": {"equals": {"indexedVariables": 5}},
642            "large_array": {"equals": {"indexedVariables": 200}},
643            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
644            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
645            "pt": {"missing": ["indexedVariables"]},
646        }
647        self.verify_variables(verify_locals, locals)
648
649        # We also verify that we produce a "[raw]" fake child with the real
650        # SBValue for the synthetic type.
651        verify_children = {
652            "[0]": {"equals": {"type": "int", "value": "0"}},
653            "[1]": {"equals": {"type": "int", "value": "0"}},
654            "[2]": {"equals": {"type": "int", "value": "0"}},
655            "[3]": {"equals": {"type": "int", "value": "0"}},
656            "[4]": {"equals": {"type": "int", "value": "0"}},
657        }
658        if enableSyntheticChildDebugging:
659            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
660
661        children = self.dap_server.request_variables(locals[2]["variablesReference"])[
662            "body"
663        ]["variables"]
664        self.verify_variables(verify_children, children)
665
666    @skipIfWindows
667    @skipIfRemote
668    def test_indexedVariables(self):
669        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
670
671    @skipIfWindows
672    @skipIfRemote
673    def test_indexedVariables_with_raw_child_for_synthetics(self):
674        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
675
676    @skipIfWindows
677    @skipIfRemote
678    def test_registers(self):
679        """
680        Test that registers whose byte size is the size of a pointer on
681        the current system get formatted as lldb::eFormatAddressInfo. This
682        will show the pointer value followed by a description of the address
683        itself. To test this we attempt to find the PC value in the general
684        purpose registers, and since we will be stopped in main.cpp, verify
685        that the value for the PC starts with a pointer and is followed by
686        a description that contains main.cpp.
687        """
688        program = self.getBuildArtifact("a.out")
689        self.build_and_launch(program)
690        source = "main.cpp"
691        breakpoint1_line = line_number(source, "// breakpoint 1")
692        lines = [breakpoint1_line]
693        # Set breakpoint in the thread function so we can step the threads
694        breakpoint_ids = self.set_source_breakpoints(source, lines)
695        self.assertEqual(
696            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
697        )
698        self.continue_to_breakpoints(breakpoint_ids)
699
700        pc_name = None
701        arch = self.getArchitecture()
702        if arch == "x86_64":
703            pc_name = "rip"
704        elif arch == "x86":
705            pc_name = "rip"
706        elif arch.startswith("arm"):
707            pc_name = "pc"
708
709        if pc_name is None:
710            return
711        # Verify locals
712        reg_sets = self.dap_server.get_registers()
713        for reg_set in reg_sets:
714            if reg_set["name"] == "General Purpose Registers":
715                varRef = reg_set["variablesReference"]
716                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
717                for reg in regs:
718                    if reg["name"] == pc_name:
719                        value = reg["value"]
720                        self.assertTrue(value.startswith("0x"))
721                        self.assertIn("a.out`main + ", value)
722                        self.assertIn("at main.cpp:", value)
723
724    @no_debug_info_test
725    @skipUnlessDarwin
726    def test_darwin_dwarf_missing_obj(self):
727        """
728        Test that if we build a binary with DWARF in .o files and we remove
729        the .o file for main.cpp, that we get a variable named "<error>"
730        whose value matches the appriopriate error. Errors when getting
731        variables are returned in the LLDB API when the user should be
732        notified of issues that can easily be solved by rebuilding or
733        changing compiler options and are designed to give better feedback
734        to the user.
735        """
736        self.darwin_dwarf_missing_obj(None)
737
738    @no_debug_info_test
739    @skipUnlessDarwin
740    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
741        """
742        Test that if we build a binary with DWARF in .o files and we remove
743        the .o file for main.cpp, that we get a variable named "<error>"
744        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
745        """
746        initCommands = ["settings set symbols.load-on-demand true"]
747        self.darwin_dwarf_missing_obj(initCommands)
748
749    @no_debug_info_test
750    @skipIfWindows
751    @skipIfRemote
752    def test_value_format(self):
753        """
754        Test that toggle variables value format between decimal and hexical works.
755        """
756        program = self.getBuildArtifact("a.out")
757        self.build_and_launch(program)
758        source = "main.cpp"
759        breakpoint1_line = line_number(source, "// breakpoint 1")
760        lines = [breakpoint1_line]
761
762        breakpoint_ids = self.set_source_breakpoints(source, lines)
763        self.assertEqual(
764            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
765        )
766        self.continue_to_breakpoints(breakpoint_ids)
767
768        # Verify locals value format decimal
769        is_hex = False
770        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
771        self.assertEqual(var_pt_x["value"], "11")
772        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
773        self.assertEqual(var_pt_y["value"], "22")
774
775        # Verify locals value format hexical
776        is_hex = True
777        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
778        self.assertEqual(var_pt_x["value"], "0x0000000b")
779        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
780        self.assertEqual(var_pt_y["value"], "0x00000016")
781
782        # Toggle and verify locals value format decimal again
783        is_hex = False
784        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
785        self.assertEqual(var_pt_x["value"], "11")
786        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
787        self.assertEqual(var_pt_y["value"], "22")
788