xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision fa6377119c0624773cb698935692d46843e9f6ec)
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    def test_scopes_variables_setVariable_evaluate(self):
398        self.do_test_scopes_variables_setVariable_evaluate(
399            enableAutoVariableSummaries=False
400        )
401
402    @skipIfWindows
403    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
404        self.do_test_scopes_variables_setVariable_evaluate(
405            enableAutoVariableSummaries=True
406        )
407
408    def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):
409        """
410        Tests the evaluated expression expands successfully after "scopes" packets
411        and permanent expressions persist.
412        """
413        program = self.getBuildArtifact("a.out")
414        self.build_and_launch(
415            program, enableAutoVariableSummaries=enableAutoVariableSummaries
416        )
417        source = "main.cpp"
418        breakpoint1_line = line_number(source, "// breakpoint 1")
419        lines = [breakpoint1_line]
420        # Set breakpoint in the thread function so we can step the threads
421        breakpoint_ids = self.set_source_breakpoints(source, lines)
422        self.assertEqual(
423            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
424        )
425        self.continue_to_breakpoints(breakpoint_ids)
426
427        # Verify locals
428        locals = self.dap_server.get_local_variables()
429        buffer_children = make_buffer_verify_dict(0, 32)
430        verify_locals = {
431            "argc": {
432                "equals": {"type": "int", "value": "1"},
433                "missing": ["indexedVariables"],
434            },
435            "argv": {
436                "equals": {"type": "const char **"},
437                "startswith": {"value": "0x"},
438                "hasVariablesReference": True,
439                "missing": ["indexedVariables"],
440            },
441            "pt": {
442                "equals": {"type": "PointType"},
443                "hasVariablesReference": True,
444                "missing": ["indexedVariables"],
445                "children": {
446                    "x": {
447                        "equals": {"type": "int", "value": "11"},
448                        "missing": ["indexedVariables"],
449                    },
450                    "y": {
451                        "equals": {"type": "int", "value": "22"},
452                        "missing": ["indexedVariables"],
453                    },
454                    "buffer": {
455                        "children": buffer_children,
456                        "equals": {"indexedVariables": 16},
457                    },
458                },
459            },
460            "x": {
461                "equals": {"type": "int"},
462                "missing": ["indexedVariables"],
463            },
464        }
465        self.verify_variables(verify_locals, locals)
466
467        # Evaluate expandable expression twice: once permanent (from repl)
468        # the other temporary (from other UI).
469        expandable_expression = {
470            "name": "pt",
471            "context": {
472                "repl": {
473                    "equals": {"type": "PointType"},
474                    "equals": {
475                        "result": """(PointType) $0 = {
476  x = 11
477  y = 22
478  buffer = {
479    [0] = 0
480    [1] = 1
481    [2] = 2
482    [3] = 3
483    [4] = 4
484    [5] = 5
485    [6] = 6
486    [7] = 7
487    [8] = 8
488    [9] = 9
489    [10] = 10
490    [11] = 11
491    [12] = 12
492    [13] = 13
493    [14] = 14
494    [15] = 15
495  }
496}"""
497                    },
498                    "missing": ["indexedVariables"],
499                    "hasVariablesReference": True,
500                },
501                "hover": {
502                    "equals": {"type": "PointType"},
503                    "startswith": {
504                        "result": (
505                            "{x:11, y:22, buffer:{...}}"
506                            if enableAutoVariableSummaries
507                            else "PointType @ 0x"
508                        )
509                    },
510                    "missing": ["indexedVariables"],
511                    "hasVariablesReference": True,
512                },
513                "watch": {
514                    "equals": {"type": "PointType"},
515                    "startswith": {
516                        "result": (
517                            "{x:11, y:22, buffer:{...}}"
518                            if enableAutoVariableSummaries
519                            else "PointType @ 0x"
520                        )
521                    },
522                    "missing": ["indexedVariables"],
523                    "hasVariablesReference": True,
524                },
525                "variables": {
526                    "equals": {"type": "PointType"},
527                    "startswith": {
528                        "result": (
529                            "{x:11, y:22, buffer:{...}}"
530                            if enableAutoVariableSummaries
531                            else "PointType @ 0x"
532                        )
533                    },
534                    "missing": ["indexedVariables"],
535                    "hasVariablesReference": True,
536                },
537            },
538            "children": {
539                "x": {"equals": {"type": "int", "value": "11"}},
540                "y": {"equals": {"type": "int", "value": "22"}},
541                "buffer": {"children": buffer_children},
542            },
543        }
544
545        # Evaluate from known contexts.
546        expr_varref_dict = {}
547        for context, verify_dict in expandable_expression["context"].items():
548            response = self.dap_server.request_evaluate(
549                expandable_expression["name"],
550                frameIndex=0,
551                threadId=None,
552                context=context,
553            )
554            self.verify_values(
555                verify_dict,
556                response["body"],
557                expr_varref_dict,
558                expandable_expression["name"],
559            )
560
561        # Evaluate locals again.
562        locals = self.dap_server.get_local_variables()
563        self.verify_variables(verify_locals, locals)
564
565        # Verify the evaluated expressions before second locals evaluation
566        # can be expanded.
567        var_ref = expr_varref_dict[expandable_expression["name"]]
568        response = self.dap_server.request_variables(var_ref)
569        self.verify_variables(
570            expandable_expression["children"], response["body"]["variables"]
571        )
572
573        # Continue to breakpoint 3, permanent variable should still exist
574        # after resume.
575        breakpoint3_line = line_number(source, "// breakpoint 3")
576        lines = [breakpoint3_line]
577        breakpoint_ids = self.set_source_breakpoints(source, lines)
578        self.assertEqual(
579            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
580        )
581        self.continue_to_breakpoints(breakpoint_ids)
582
583        var_ref = expr_varref_dict[expandable_expression["name"]]
584        response = self.dap_server.request_variables(var_ref)
585        self.verify_variables(
586            expandable_expression["children"], response["body"]["variables"]
587        )
588
589        # Test that frame scopes have corresponding presentation hints.
590        frame_id = self.dap_server.get_stackFrame()["id"]
591        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
592
593        scope_names = [scope["name"] for scope in scopes]
594        self.assertIn("Locals", scope_names)
595        self.assertIn("Registers", scope_names)
596
597        for scope in scopes:
598            if scope["name"] == "Locals":
599                self.assertEqual(scope.get("presentationHint"), "locals")
600            if scope["name"] == "Registers":
601                self.assertEqual(scope.get("presentationHint"), "registers")
602
603    @skipIfWindows
604    def test_scopes_and_evaluate_expansion(self):
605        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
606
607    @skipIfWindows
608    def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
609        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
610
611    def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
612        """
613        Tests that arrays and lldb.SBValue objects that have synthetic child
614        providers have "indexedVariables" key/value pairs. This helps the IDE
615        not to fetch too many children all at once.
616        """
617        program = self.getBuildArtifact("a.out")
618        self.build_and_launch(
619            program, enableSyntheticChildDebugging=enableSyntheticChildDebugging
620        )
621        source = "main.cpp"
622        breakpoint1_line = line_number(source, "// breakpoint 4")
623        lines = [breakpoint1_line]
624        # Set breakpoint in the thread function so we can step the threads
625        breakpoint_ids = self.set_source_breakpoints(source, lines)
626        self.assertEqual(
627            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
628        )
629        self.continue_to_breakpoints(breakpoint_ids)
630
631        # Verify locals
632        locals = self.dap_server.get_local_variables()
633        # The vector variables might have one additional entry from the fake
634        # "[raw]" child.
635        raw_child_count = 1 if enableSyntheticChildDebugging else 0
636        verify_locals = {
637            "small_array": {"equals": {"indexedVariables": 5}},
638            "large_array": {"equals": {"indexedVariables": 200}},
639            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
640            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
641            "pt": {"missing": ["indexedVariables"]},
642        }
643        self.verify_variables(verify_locals, locals)
644
645        # We also verify that we produce a "[raw]" fake child with the real
646        # SBValue for the synthetic type.
647        verify_children = {
648            "[0]": {"equals": {"type": "int", "value": "0"}},
649            "[1]": {"equals": {"type": "int", "value": "0"}},
650            "[2]": {"equals": {"type": "int", "value": "0"}},
651            "[3]": {"equals": {"type": "int", "value": "0"}},
652            "[4]": {"equals": {"type": "int", "value": "0"}},
653        }
654        if enableSyntheticChildDebugging:
655            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
656
657        children = self.dap_server.request_variables(locals[2]["variablesReference"])[
658            "body"
659        ]["variables"]
660        self.verify_variables(verify_children, children)
661
662    @skipIfWindows
663    def test_indexedVariables(self):
664        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
665
666    @skipIfWindows
667    def test_indexedVariables_with_raw_child_for_synthetics(self):
668        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
669
670    @skipIfWindows
671    def test_registers(self):
672        """
673        Test that registers whose byte size is the size of a pointer on
674        the current system get formatted as lldb::eFormatAddressInfo. This
675        will show the pointer value followed by a description of the address
676        itself. To test this we attempt to find the PC value in the general
677        purpose registers, and since we will be stopped in main.cpp, verify
678        that the value for the PC starts with a pointer and is followed by
679        a description that contains main.cpp.
680        """
681        program = self.getBuildArtifact("a.out")
682        self.build_and_launch(program)
683        source = "main.cpp"
684        breakpoint1_line = line_number(source, "// breakpoint 1")
685        lines = [breakpoint1_line]
686        # Set breakpoint in the thread function so we can step the threads
687        breakpoint_ids = self.set_source_breakpoints(source, lines)
688        self.assertEqual(
689            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
690        )
691        self.continue_to_breakpoints(breakpoint_ids)
692
693        pc_name = None
694        arch = self.getArchitecture()
695        if arch == "x86_64":
696            pc_name = "rip"
697        elif arch == "x86":
698            pc_name = "rip"
699        elif arch.startswith("arm"):
700            pc_name = "pc"
701
702        if pc_name is None:
703            return
704        # Verify locals
705        reg_sets = self.dap_server.get_registers()
706        for reg_set in reg_sets:
707            if reg_set["name"] == "General Purpose Registers":
708                varRef = reg_set["variablesReference"]
709                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
710                for reg in regs:
711                    if reg["name"] == pc_name:
712                        value = reg["value"]
713                        self.assertTrue(value.startswith("0x"))
714                        self.assertIn("a.out`main + ", value)
715                        self.assertIn("at main.cpp:", value)
716
717    @no_debug_info_test
718    @skipUnlessDarwin
719    def test_darwin_dwarf_missing_obj(self):
720        """
721        Test that if we build a binary with DWARF in .o files and we remove
722        the .o file for main.cpp, that we get a variable named "<error>"
723        whose value matches the appriopriate error. Errors when getting
724        variables are returned in the LLDB API when the user should be
725        notified of issues that can easily be solved by rebuilding or
726        changing compiler options and are designed to give better feedback
727        to the user.
728        """
729        self.darwin_dwarf_missing_obj(None)
730
731    @no_debug_info_test
732    @skipUnlessDarwin
733    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
734        """
735        Test that if we build a binary with DWARF in .o files and we remove
736        the .o file for main.cpp, that we get a variable named "<error>"
737        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
738        """
739        initCommands = ["settings set symbols.load-on-demand true"]
740        self.darwin_dwarf_missing_obj(initCommands)
741
742    @no_debug_info_test
743    @skipIfWindows
744    def test_value_format(self):
745        """
746        Test that toggle variables value format between decimal and hexical works.
747        """
748        program = self.getBuildArtifact("a.out")
749        self.build_and_launch(program)
750        source = "main.cpp"
751        breakpoint1_line = line_number(source, "// breakpoint 1")
752        lines = [breakpoint1_line]
753
754        breakpoint_ids = self.set_source_breakpoints(source, lines)
755        self.assertEqual(
756            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
757        )
758        self.continue_to_breakpoints(breakpoint_ids)
759
760        # Verify locals value format decimal
761        is_hex = False
762        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
763        self.assertEqual(var_pt_x["value"], "11")
764        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
765        self.assertEqual(var_pt_y["value"], "22")
766
767        # Verify locals value format hexical
768        is_hex = True
769        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
770        self.assertEqual(var_pt_x["value"], "0x0000000b")
771        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
772        self.assertEqual(var_pt_y["value"], "0x00000016")
773
774        # Toggle and verify locals value format decimal again
775        is_hex = False
776        var_pt_x = self.dap_server.get_local_variable_child("pt", "x", is_hex=is_hex)
777        self.assertEqual(var_pt_x["value"], "11")
778        var_pt_y = self.dap_server.get_local_variable_child("pt", "y", is_hex=is_hex)
779        self.assertEqual(var_pt_y["value"], "22")
780