xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision a3cd8d76deeea89a56875f2e2aced8afba13f441)
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
204        verify_globals = {
205            "s_local": {"equals": {"type": "float", "value": "2.25"}},
206        }
207        s_global = {"equals": {"type": "int", "value": "234"}}
208        g_global = {"equals": {"type": "int", "value": "123"}}
209        if lldbplatformutil.getHostPlatform() == "windows":
210            verify_globals["::s_global"] = s_global
211            verify_globals["g_global"] = g_global
212        else:
213            verify_globals["s_global"] = s_global
214            verify_globals["::g_global"] = g_global
215
216        varref_dict = {}
217        self.verify_variables(verify_locals, locals, varref_dict)
218        self.verify_variables(verify_globals, globals, varref_dict)
219        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
220        # We need to test the functionality of the "variables" request as it
221        # has optional parameters like "start" and "count" to limit the number
222        # of variables that are fetched
223        varRef = varref_dict["pt.buffer"]
224        response = self.dap_server.request_variables(varRef)
225        self.verify_variables(buffer_children, response["body"]["variables"])
226        # Verify setting start=0 in the arguments still gets all children
227        response = self.dap_server.request_variables(varRef, start=0)
228        self.verify_variables(buffer_children, response["body"]["variables"])
229        # Verify setting count=0 in the arguments still gets all children.
230        # If count is zero, it means to get all children.
231        response = self.dap_server.request_variables(varRef, count=0)
232        self.verify_variables(buffer_children, response["body"]["variables"])
233        # Verify setting count to a value that is too large in the arguments
234        # still gets all children, and no more
235        response = self.dap_server.request_variables(varRef, count=1000)
236        self.verify_variables(buffer_children, response["body"]["variables"])
237        # Verify setting the start index and count gets only the children we
238        # want
239        response = self.dap_server.request_variables(varRef, start=5, count=5)
240        self.verify_variables(
241            make_buffer_verify_dict(5, 5), response["body"]["variables"]
242        )
243        # Verify setting the start index to a value that is out of range
244        # results in an empty list
245        response = self.dap_server.request_variables(varRef, start=32, count=1)
246        self.assertEqual(
247            len(response["body"]["variables"]),
248            0,
249            "verify we get no variable back for invalid start",
250        )
251
252        # Test evaluate
253        expressions = {
254            "pt.x": {
255                "equals": {"result": "11", "type": "int"},
256                "hasVariablesReference": False,
257            },
258            "pt.buffer[2]": {
259                "equals": {"result": "2", "type": "int"},
260                "hasVariablesReference": False,
261            },
262            "pt": {
263                "equals": {"type": "PointType"},
264                "startswith": {
265                    "result": (
266                        "{x:11, y:22, buffer:{...}}"
267                        if enableAutoVariableSummaries
268                        else "PointType @ 0x"
269                    )
270                },
271                "hasVariablesReference": True,
272            },
273            "pt.buffer": {
274                "equals": {"type": "int[16]"},
275                "startswith": {
276                    "result": (
277                        "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
278                        if enableAutoVariableSummaries
279                        else "int[16] @ 0x"
280                    )
281                },
282                "hasVariablesReference": True,
283            },
284            "argv": {
285                "equals": {"type": "const char **"},
286                "startswith": {"result": "0x"},
287                "hasVariablesReference": True,
288            },
289            "argv[0]": {
290                "equals": {"type": "const char *"},
291                "startswith": {"result": "0x"},
292                "hasVariablesReference": True,
293            },
294            "2+3": {
295                "equals": {"result": "5", "type": "int"},
296                "hasVariablesReference": False,
297            },
298        }
299        for expression in expressions:
300            response = self.dap_server.request_evaluate(expression)
301            self.verify_values(expressions[expression], response["body"])
302
303        # Test setting variables
304        self.set_local("argc", 123)
305        argc = self.get_local_as_int("argc")
306        self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % (argc))
307
308        self.set_local("argv", 0x1234)
309        argv = self.get_local_as_int("argv")
310        self.assertEqual(
311            argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % (argv)
312        )
313
314        # Set a variable value whose name is synthetic, like a variable index
315        # and verify the value by reading it
316        self.dap_server.request_setVariable(varRef, "[0]", 100)
317        response = self.dap_server.request_variables(varRef, start=0, count=1)
318        self.verify_variables(
319            make_buffer_verify_dict(0, 1, 100), response["body"]["variables"]
320        )
321
322        # Set a variable value whose name is a real child value, like "pt.x"
323        # and verify the value by reading it
324        varRef = varref_dict["pt"]
325        self.dap_server.request_setVariable(varRef, "x", 111)
326        response = self.dap_server.request_variables(varRef, start=0, count=1)
327        value = response["body"]["variables"][0]["value"]
328        self.assertEqual(
329            value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)
330        )
331
332        # We check shadowed variables and that a new get_local_variables request
333        # gets the right data
334        breakpoint2_line = line_number(source, "// breakpoint 2")
335        lines = [breakpoint2_line]
336        breakpoint_ids = self.set_source_breakpoints(source, lines)
337        self.assertEqual(
338            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
339        )
340        self.continue_to_breakpoints(breakpoint_ids)
341
342        verify_locals["argc"]["equals"]["value"] = "123"
343        verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
344        verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
345        verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
346        verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
347
348        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
349
350        # Now we verify that we correctly change the name of a variable with and without differentiator suffix
351        self.assertFalse(self.dap_server.request_setVariable(1, "x2", 9)["success"])
352        self.assertFalse(
353            self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"]
354        )
355
356        self.assertTrue(
357            self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
358        )
359        self.assertTrue(
360            self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
361        )
362        self.assertTrue(
363            self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
364        )
365
366        # The following should have no effect
367        self.assertFalse(
368            self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[
369                "success"
370            ]
371        )
372
373        verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
374        verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
375        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
376
377        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
378
379        # The plain x variable shold refer to the innermost x
380        self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"])
381        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
382
383        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
384
385        # In breakpoint 3, there should be no shadowed variables
386        breakpoint3_line = line_number(source, "// breakpoint 3")
387        lines = [breakpoint3_line]
388        breakpoint_ids = self.set_source_breakpoints(source, lines)
389        self.assertEqual(
390            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
391        )
392        self.continue_to_breakpoints(breakpoint_ids)
393
394        locals = self.dap_server.get_local_variables()
395        names = [var["name"] for var in locals]
396        # The first shadowed x shouldn't have a suffix anymore
397        verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
398        self.assertNotIn("x @ main.cpp:17", names)
399        self.assertNotIn("x @ main.cpp:19", names)
400        self.assertNotIn("x @ main.cpp:21", names)
401
402        self.verify_variables(verify_locals, locals)
403
404    def test_scopes_variables_setVariable_evaluate(self):
405        self.do_test_scopes_variables_setVariable_evaluate(
406            enableAutoVariableSummaries=False
407        )
408
409    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
410        self.do_test_scopes_variables_setVariable_evaluate(
411            enableAutoVariableSummaries=True
412        )
413
414    def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):
415        """
416        Tests the evaluated expression expands successfully after "scopes" packets
417        and permanent expressions persist.
418        """
419        program = self.getBuildArtifact("a.out")
420        self.build_and_launch(
421            program, enableAutoVariableSummaries=enableAutoVariableSummaries
422        )
423        source = "main.cpp"
424        breakpoint1_line = line_number(source, "// breakpoint 1")
425        lines = [breakpoint1_line]
426        # Set breakpoint in the thread function so we can step the threads
427        breakpoint_ids = self.set_source_breakpoints(source, lines)
428        self.assertEqual(
429            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
430        )
431        self.continue_to_breakpoints(breakpoint_ids)
432
433        # Verify locals
434        locals = self.dap_server.get_local_variables()
435        buffer_children = make_buffer_verify_dict(0, 32)
436        verify_locals = {
437            "argc": {
438                "equals": {"type": "int", "value": "1"},
439                "missing": ["indexedVariables"],
440            },
441            "argv": {
442                "equals": {"type": "const char **"},
443                "startswith": {"value": "0x"},
444                "hasVariablesReference": True,
445                "missing": ["indexedVariables"],
446            },
447            "pt": {
448                "equals": {"type": "PointType"},
449                "hasVariablesReference": True,
450                "missing": ["indexedVariables"],
451                "children": {
452                    "x": {
453                        "equals": {"type": "int", "value": "11"},
454                        "missing": ["indexedVariables"],
455                    },
456                    "y": {
457                        "equals": {"type": "int", "value": "22"},
458                        "missing": ["indexedVariables"],
459                    },
460                    "buffer": {
461                        "children": buffer_children,
462                        "equals": {"indexedVariables": 16},
463                    },
464                },
465            },
466            "x": {
467                "equals": {"type": "int"},
468                "missing": ["indexedVariables"],
469            },
470        }
471        self.verify_variables(verify_locals, locals)
472
473        # Evaluate expandable expression twice: once permanent (from repl)
474        # the other temporary (from other UI).
475        expandable_expression = {
476            "name": "pt",
477            "context": {
478                "repl": {
479                    "equals": {"type": "PointType"},
480                    "equals": {
481                        "result": """(PointType) $0 = {
482  x = 11
483  y = 22
484  buffer = {
485    [0] = 0
486    [1] = 1
487    [2] = 2
488    [3] = 3
489    [4] = 4
490    [5] = 5
491    [6] = 6
492    [7] = 7
493    [8] = 8
494    [9] = 9
495    [10] = 10
496    [11] = 11
497    [12] = 12
498    [13] = 13
499    [14] = 14
500    [15] = 15
501  }
502}"""
503                    },
504                    "missing": ["indexedVariables"],
505                    "hasVariablesReference": True,
506                },
507                "hover": {
508                    "equals": {"type": "PointType"},
509                    "startswith": {
510                        "result": (
511                            "{x:11, y:22, buffer:{...}}"
512                            if enableAutoVariableSummaries
513                            else "PointType @ 0x"
514                        )
515                    },
516                    "missing": ["indexedVariables"],
517                    "hasVariablesReference": True,
518                },
519                "watch": {
520                    "equals": {"type": "PointType"},
521                    "startswith": {
522                        "result": (
523                            "{x:11, y:22, buffer:{...}}"
524                            if enableAutoVariableSummaries
525                            else "PointType @ 0x"
526                        )
527                    },
528                    "missing": ["indexedVariables"],
529                    "hasVariablesReference": True,
530                },
531                "variables": {
532                    "equals": {"type": "PointType"},
533                    "startswith": {
534                        "result": (
535                            "{x:11, y:22, buffer:{...}}"
536                            if enableAutoVariableSummaries
537                            else "PointType @ 0x"
538                        )
539                    },
540                    "missing": ["indexedVariables"],
541                    "hasVariablesReference": True,
542                },
543            },
544            "children": {
545                "x": {"equals": {"type": "int", "value": "11"}},
546                "y": {"equals": {"type": "int", "value": "22"}},
547                "buffer": {"children": buffer_children},
548            },
549        }
550
551        # Evaluate from known contexts.
552        expr_varref_dict = {}
553        for context, verify_dict in expandable_expression["context"].items():
554            response = self.dap_server.request_evaluate(
555                expandable_expression["name"],
556                frameIndex=0,
557                threadId=None,
558                context=context,
559            )
560            self.verify_values(
561                verify_dict,
562                response["body"],
563                expr_varref_dict,
564                expandable_expression["name"],
565            )
566
567        # Evaluate locals again.
568        locals = self.dap_server.get_local_variables()
569        self.verify_variables(verify_locals, locals)
570
571        # Verify the evaluated expressions before second locals evaluation
572        # can be expanded.
573        var_ref = expr_varref_dict[expandable_expression["name"]]
574        response = self.dap_server.request_variables(var_ref)
575        self.verify_variables(
576            expandable_expression["children"], response["body"]["variables"]
577        )
578
579        # Continue to breakpoint 3, permanent variable should still exist
580        # after resume.
581        breakpoint3_line = line_number(source, "// breakpoint 3")
582        lines = [breakpoint3_line]
583        breakpoint_ids = self.set_source_breakpoints(source, lines)
584        self.assertEqual(
585            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
586        )
587        self.continue_to_breakpoints(breakpoint_ids)
588
589        var_ref = expr_varref_dict[expandable_expression["name"]]
590        response = self.dap_server.request_variables(var_ref)
591        self.verify_variables(
592            expandable_expression["children"], response["body"]["variables"]
593        )
594
595        # Test that frame scopes have corresponding presentation hints.
596        frame_id = self.dap_server.get_stackFrame()["id"]
597        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
598
599        scope_names = [scope["name"] for scope in scopes]
600        self.assertIn("Locals", scope_names)
601        self.assertIn("Registers", scope_names)
602
603        for scope in scopes:
604            if scope["name"] == "Locals":
605                self.assertEqual(scope.get("presentationHint"), "locals")
606            if scope["name"] == "Registers":
607                self.assertEqual(scope.get("presentationHint"), "registers")
608
609    def test_scopes_and_evaluate_expansion(self):
610        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
611
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    def test_indexedVariables(self):
668        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
669
670    @skipIfWindows
671    def test_indexedVariables_with_raw_child_for_synthetics(self):
672        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
673
674    @skipIfWindows
675    def test_registers(self):
676        """
677        Test that registers whose byte size is the size of a pointer on
678        the current system get formatted as lldb::eFormatAddressInfo. This
679        will show the pointer value followed by a description of the address
680        itself. To test this we attempt to find the PC value in the general
681        purpose registers, and since we will be stopped in main.cpp, verify
682        that the value for the PC starts with a pointer and is followed by
683        a description that contains main.cpp.
684        """
685        program = self.getBuildArtifact("a.out")
686        self.build_and_launch(program)
687        source = "main.cpp"
688        breakpoint1_line = line_number(source, "// breakpoint 1")
689        lines = [breakpoint1_line]
690        # Set breakpoint in the thread function so we can step the threads
691        breakpoint_ids = self.set_source_breakpoints(source, lines)
692        self.assertEqual(
693            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
694        )
695        self.continue_to_breakpoints(breakpoint_ids)
696
697        pc_name = None
698        arch = self.getArchitecture()
699        if arch == "x86_64":
700            pc_name = "rip"
701        elif arch == "x86":
702            pc_name = "rip"
703        elif arch.startswith("arm"):
704            pc_name = "pc"
705
706        if pc_name is None:
707            return
708        # Verify locals
709        reg_sets = self.dap_server.get_registers()
710        for reg_set in reg_sets:
711            if reg_set["name"] == "General Purpose Registers":
712                varRef = reg_set["variablesReference"]
713                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
714                for reg in regs:
715                    if reg["name"] == pc_name:
716                        value = reg["value"]
717                        self.assertTrue(value.startswith("0x"))
718                        self.assertIn("a.out`main + ", value)
719                        self.assertIn("at main.cpp:", value)
720
721    @no_debug_info_test
722    @skipUnlessDarwin
723    def test_darwin_dwarf_missing_obj(self):
724        """
725        Test that if we build a binary with DWARF in .o files and we remove
726        the .o file for main.cpp, that we get a variable named "<error>"
727        whose value matches the appriopriate error. Errors when getting
728        variables are returned in the LLDB API when the user should be
729        notified of issues that can easily be solved by rebuilding or
730        changing compiler options and are designed to give better feedback
731        to the user.
732        """
733        self.darwin_dwarf_missing_obj(None)
734
735    @no_debug_info_test
736    @skipUnlessDarwin
737    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
738        """
739        Test that if we build a binary with DWARF in .o files and we remove
740        the .o file for main.cpp, that we get a variable named "<error>"
741        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
742        """
743        initCommands = ["settings set symbols.load-on-demand true"]
744        self.darwin_dwarf_missing_obj(initCommands)
745
746    @no_debug_info_test
747    @skipIfWindows
748    def test_value_format(self):
749        """
750        Test that toggle variables value format between decimal and hexical works.
751        """
752        program = self.getBuildArtifact("a.out")
753        self.build_and_launch(program)
754        source = "main.cpp"
755        breakpoint1_line = line_number(source, "// breakpoint 1")
756        lines = [breakpoint1_line]
757
758        breakpoint_ids = self.set_source_breakpoints(source, lines)
759        self.assertEqual(
760            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
761        )
762        self.continue_to_breakpoints(breakpoint_ids)
763
764        # Verify locals value format decimal
765        is_hex = False
766        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
767        self.assertEqual(var_pt_x["value"], "11")
768        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
769        self.assertEqual(var_pt_y["value"], "22")
770
771        # Verify locals value format hexical
772        is_hex = True
773        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
774        self.assertEqual(var_pt_x["value"], "0x0000000b")
775        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
776        self.assertEqual(var_pt_y["value"], "0x00000016")
777
778        # Toggle and verify locals value format decimal again
779        is_hex = False
780        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
781        self.assertEqual(var_pt_x["value"], "11")
782        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
783        self.assertEqual(var_pt_y["value"], "22")
784