xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision 8f18f36b4906872ee0838ade2c0367c77b6f5bc0)
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    @skipIfAsan # FIXME this fails with a non-asan issue on green dragon.
676    def test_registers(self):
677        """
678        Test that registers whose byte size is the size of a pointer on
679        the current system get formatted as lldb::eFormatAddressInfo. This
680        will show the pointer value followed by a description of the address
681        itself. To test this we attempt to find the PC value in the general
682        purpose registers, and since we will be stopped in main.cpp, verify
683        that the value for the PC starts with a pointer and is followed by
684        a description that contains main.cpp.
685        """
686        program = self.getBuildArtifact("a.out")
687        self.build_and_launch(program)
688        source = "main.cpp"
689        breakpoint1_line = line_number(source, "// breakpoint 1")
690        lines = [breakpoint1_line]
691        # Set breakpoint in the thread function so we can step the threads
692        breakpoint_ids = self.set_source_breakpoints(source, lines)
693        self.assertEqual(
694            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
695        )
696        self.continue_to_breakpoints(breakpoint_ids)
697
698        pc_name = None
699        arch = self.getArchitecture()
700        if arch == "x86_64":
701            pc_name = "rip"
702        elif arch == "x86":
703            pc_name = "rip"
704        elif arch.startswith("arm"):
705            pc_name = "pc"
706
707        if pc_name is None:
708            return
709        # Verify locals
710        reg_sets = self.dap_server.get_registers()
711        for reg_set in reg_sets:
712            if reg_set["name"] == "General Purpose Registers":
713                varRef = reg_set["variablesReference"]
714                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
715                for reg in regs:
716                    if reg["name"] == pc_name:
717                        value = reg["value"]
718                        self.assertTrue(value.startswith("0x"))
719                        self.assertIn("a.out`main + ", value)
720                        self.assertIn("at main.cpp:", value)
721
722    @no_debug_info_test
723    @skipUnlessDarwin
724    def test_darwin_dwarf_missing_obj(self):
725        """
726        Test that if we build a binary with DWARF in .o files and we remove
727        the .o file for main.cpp, that we get a variable named "<error>"
728        whose value matches the appriopriate error. Errors when getting
729        variables are returned in the LLDB API when the user should be
730        notified of issues that can easily be solved by rebuilding or
731        changing compiler options and are designed to give better feedback
732        to the user.
733        """
734        self.darwin_dwarf_missing_obj(None)
735
736    @no_debug_info_test
737    @skipUnlessDarwin
738    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
739        """
740        Test that if we build a binary with DWARF in .o files and we remove
741        the .o file for main.cpp, that we get a variable named "<error>"
742        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
743        """
744        initCommands = ["settings set symbols.load-on-demand true"]
745        self.darwin_dwarf_missing_obj(initCommands)
746
747    @no_debug_info_test
748    @skipIfWindows
749    def test_value_format(self):
750        """
751        Test that toggle variables value format between decimal and hexical works.
752        """
753        program = self.getBuildArtifact("a.out")
754        self.build_and_launch(program)
755        source = "main.cpp"
756        breakpoint1_line = line_number(source, "// breakpoint 1")
757        lines = [breakpoint1_line]
758
759        breakpoint_ids = self.set_source_breakpoints(source, lines)
760        self.assertEqual(
761            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
762        )
763        self.continue_to_breakpoints(breakpoint_ids)
764
765        # Verify locals value format decimal
766        is_hex = False
767        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
768        self.assertEqual(var_pt_x["value"], "11")
769        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
770        self.assertEqual(var_pt_y["value"], "22")
771
772        # Verify locals value format hexical
773        is_hex = True
774        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
775        self.assertEqual(var_pt_x["value"], "0x0000000b")
776        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
777        self.assertEqual(var_pt_y["value"], "0x00000016")
778
779        # Toggle and verify locals value format decimal again
780        is_hex = False
781        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
782        self.assertEqual(var_pt_x["value"], "11")
783        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
784        self.assertEqual(var_pt_y["value"], "22")
785