xref: /llvm-project/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py (revision ffd173ba0b4a6d84f45308e78cea4af611bec10e)
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 "contains" in verify_dict:
46            verify = verify_dict["contains"]
47            for key in verify:
48                contains_array = verify[key]
49                actual_value = actual[key]
50                self.assertTrue(isinstance(contains_array, list))
51                for verify_value in contains_array:
52                    self.assertIn(verify_value, actual_value)
53        if "missing" in verify_dict:
54            missing = verify_dict["missing"]
55            for key in missing:
56                self.assertTrue(
57                    key not in actual, 'key "%s" is not expected in %s' % (key, actual)
58                )
59        hasVariablesReference = "variablesReference" in actual
60        varRef = None
61        if hasVariablesReference:
62            # Remember variable references in case we want to test further
63            # by using the evaluate name.
64            varRef = actual["variablesReference"]
65            if varRef != 0 and varref_dict is not None:
66                if expression is None:
67                    evaluateName = actual["evaluateName"]
68                else:
69                    evaluateName = expression
70                varref_dict[evaluateName] = varRef
71        if (
72            "hasVariablesReference" in verify_dict
73            and verify_dict["hasVariablesReference"]
74        ):
75            self.assertTrue(hasVariablesReference, "verify variable reference")
76        if "children" in verify_dict:
77            self.assertTrue(
78                hasVariablesReference and varRef is not None and varRef != 0,
79                ("children verify values specified for " "variable without children"),
80            )
81
82            response = self.dap_server.request_variables(varRef)
83            self.verify_variables(
84                verify_dict["children"], response["body"]["variables"], varref_dict
85            )
86
87    def verify_variables(self, verify_dict, variables, varref_dict=None):
88        for variable in variables:
89            name = variable["name"]
90            if not name.startswith("std::"):
91                self.assertIn(
92                    name, verify_dict, 'variable "%s" in verify dictionary' % (name)
93                )
94                self.verify_values(verify_dict[name], variable, varref_dict)
95
96    def darwin_dwarf_missing_obj(self, initCommands):
97        self.build(debug_info="dwarf")
98        program = self.getBuildArtifact("a.out")
99        main_obj = self.getBuildArtifact("main.o")
100        self.assertTrue(os.path.exists(main_obj))
101        # Delete the main.o file that contains the debug info so we force an
102        # error when we run to main and try to get variables
103        os.unlink(main_obj)
104
105        self.create_debug_adaptor()
106        self.assertTrue(os.path.exists(program), "executable must exist")
107
108        self.launch(program=program, initCommands=initCommands)
109
110        functions = ["main"]
111        breakpoint_ids = self.set_function_breakpoints(functions)
112        self.assertEquals(len(breakpoint_ids), len(functions), "expect one breakpoint")
113        self.continue_to_breakpoints(breakpoint_ids)
114
115        locals = self.dap_server.get_local_variables()
116
117        verify_locals = {
118            "<error>": {
119                "equals": {"type": "const char *"},
120                "contains": {
121                    "value": [
122                        "debug map object file ",
123                        'main.o" containing debug info does not exist, debug info will not be loaded',
124                    ]
125                },
126            },
127        }
128        varref_dict = {}
129        self.verify_variables(verify_locals, locals, varref_dict)
130
131    def do_test_scopes_variables_setVariable_evaluate(
132        self, enableAutoVariableSummaries: bool
133    ):
134        """
135        Tests the "scopes", "variables", "setVariable", and "evaluate"
136        packets.
137        """
138        program = self.getBuildArtifact("a.out")
139        self.build_and_launch(
140            program, enableAutoVariableSummaries=enableAutoVariableSummaries
141        )
142        source = "main.cpp"
143        breakpoint1_line = line_number(source, "// breakpoint 1")
144        lines = [breakpoint1_line]
145        # Set breakpoint in the thread function so we can step the threads
146        breakpoint_ids = self.set_source_breakpoints(source, lines)
147        self.assertEqual(
148            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
149        )
150        self.continue_to_breakpoints(breakpoint_ids)
151        locals = self.dap_server.get_local_variables()
152        globals = self.dap_server.get_global_variables()
153        buffer_children = make_buffer_verify_dict(0, 32)
154        verify_locals = {
155            "argc": {
156                "equals": {
157                    "type": "int",
158                    "value": "1",
159                },
160                "$__lldb_extensions": {
161                    "equals": {
162                        "value": "1",
163                    },
164                    "declaration": {
165                        "equals": {"line": 12, "column": 14},
166                        "contains": {"path": ["lldb-dap", "variables", "main.cpp"]},
167                    },
168                },
169            },
170            "argv": {
171                "equals": {"type": "const char **"},
172                "startswith": {"value": "0x"},
173                "hasVariablesReference": True,
174            },
175            "pt": {
176                "equals": {
177                    "type": "PointType",
178                },
179                "hasVariablesReference": True,
180                "children": {
181                    "x": {"equals": {"type": "int", "value": "11"}},
182                    "y": {"equals": {"type": "int", "value": "22"}},
183                    "buffer": {"children": buffer_children},
184                },
185            },
186            "x": {"equals": {"type": "int"}},
187        }
188        if enableAutoVariableSummaries:
189            verify_locals["pt"]["$__lldb_extensions"] = {
190                "equals": {"autoSummary": "{x:11, y:22}"}
191            }
192        verify_globals = {
193            "s_local": {"equals": {"type": "float", "value": "2.25"}},
194            "::g_global": {"equals": {"type": "int", "value": "123"}},
195            "s_global": {"equals": {"type": "int", "value": "234"}},
196        }
197        varref_dict = {}
198        self.verify_variables(verify_locals, locals, varref_dict)
199        self.verify_variables(verify_globals, globals, varref_dict)
200        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
201        # We need to test the functionality of the "variables" request as it
202        # has optional parameters like "start" and "count" to limit the number
203        # of variables that are fetched
204        varRef = varref_dict["pt.buffer"]
205        response = self.dap_server.request_variables(varRef)
206        self.verify_variables(buffer_children, response["body"]["variables"])
207        # Verify setting start=0 in the arguments still gets all children
208        response = self.dap_server.request_variables(varRef, start=0)
209        self.verify_variables(buffer_children, response["body"]["variables"])
210        # Verify setting count=0 in the arguments still gets all children.
211        # If count is zero, it means to get all children.
212        response = self.dap_server.request_variables(varRef, count=0)
213        self.verify_variables(buffer_children, response["body"]["variables"])
214        # Verify setting count to a value that is too large in the arguments
215        # still gets all children, and no more
216        response = self.dap_server.request_variables(varRef, count=1000)
217        self.verify_variables(buffer_children, response["body"]["variables"])
218        # Verify setting the start index and count gets only the children we
219        # want
220        response = self.dap_server.request_variables(varRef, start=5, count=5)
221        self.verify_variables(
222            make_buffer_verify_dict(5, 5), response["body"]["variables"]
223        )
224        # Verify setting the start index to a value that is out of range
225        # results in an empty list
226        response = self.dap_server.request_variables(varRef, start=32, count=1)
227        self.assertEqual(
228            len(response["body"]["variables"]),
229            0,
230            "verify we get no variable back for invalid start",
231        )
232
233        # Test evaluate
234        expressions = {
235            "pt.x": {
236                "equals": {"result": "11", "type": "int"},
237                "hasVariablesReference": False,
238            },
239            "pt.buffer[2]": {
240                "equals": {"result": "2", "type": "int"},
241                "hasVariablesReference": False,
242            },
243            "pt": {
244                "equals": {"type": "PointType"},
245                "startswith": {
246                    "result": "{x:11, y:22}"
247                    if enableAutoVariableSummaries
248                    else "PointType @ 0x"
249                },
250                "hasVariablesReference": True,
251            },
252            "pt.buffer": {
253                "equals": {"type": "int[32]"},
254                "startswith": {
255                    "result": "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...}"
256                    if enableAutoVariableSummaries
257                    else "int[32] @ 0x"
258                },
259                "hasVariablesReference": True,
260            },
261            "argv": {
262                "equals": {"type": "const char **"},
263                "startswith": {"result": "0x"},
264                "hasVariablesReference": True,
265            },
266            "argv[0]": {
267                "equals": {"type": "const char *"},
268                "startswith": {"result": "0x"},
269                "hasVariablesReference": True,
270            },
271            "2+3": {
272                "equals": {"result": "5", "type": "int"},
273                "hasVariablesReference": False,
274            },
275        }
276        for expression in expressions:
277            response = self.dap_server.request_evaluate(expression)
278            self.verify_values(expressions[expression], response["body"])
279
280        # Test setting variables
281        self.set_local("argc", 123)
282        argc = self.get_local_as_int("argc")
283        self.assertEqual(argc, 123, "verify argc was set to 123 (123 != %i)" % (argc))
284
285        self.set_local("argv", 0x1234)
286        argv = self.get_local_as_int("argv")
287        self.assertEqual(
288            argv, 0x1234, "verify argv was set to 0x1234 (0x1234 != %#x)" % (argv)
289        )
290
291        # Set a variable value whose name is synthetic, like a variable index
292        # and verify the value by reading it
293        self.dap_server.request_setVariable(varRef, "[0]", 100)
294        response = self.dap_server.request_variables(varRef, start=0, count=1)
295        self.verify_variables(
296            make_buffer_verify_dict(0, 1, 100), response["body"]["variables"]
297        )
298
299        # Set a variable value whose name is a real child value, like "pt.x"
300        # and verify the value by reading it
301        varRef = varref_dict["pt"]
302        self.dap_server.request_setVariable(varRef, "x", 111)
303        response = self.dap_server.request_variables(varRef, start=0, count=1)
304        value = response["body"]["variables"][0]["value"]
305        self.assertEqual(
306            value, "111", "verify pt.x got set to 111 (111 != %s)" % (value)
307        )
308
309        # We check shadowed variables and that a new get_local_variables request
310        # gets the right data
311        breakpoint2_line = line_number(source, "// breakpoint 2")
312        lines = [breakpoint2_line]
313        breakpoint_ids = self.set_source_breakpoints(source, lines)
314        self.assertEqual(
315            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
316        )
317        self.continue_to_breakpoints(breakpoint_ids)
318
319        verify_locals["argc"]["equals"]["value"] = "123"
320        verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
321        verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
322        verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
323        verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
324
325        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
326
327        # Now we verify that we correctly change the name of a variable with and without differentiator suffix
328        self.assertFalse(self.dap_server.request_setVariable(1, "x2", 9)["success"])
329        self.assertFalse(
330            self.dap_server.request_setVariable(1, "x @ main.cpp:0", 9)["success"]
331        )
332
333        self.assertTrue(
334            self.dap_server.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
335        )
336        self.assertTrue(
337            self.dap_server.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
338        )
339        self.assertTrue(
340            self.dap_server.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
341        )
342
343        # The following should have no effect
344        self.assertFalse(
345            self.dap_server.request_setVariable(1, "x @ main.cpp:21", "invalid")[
346                "success"
347            ]
348        )
349
350        verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
351        verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
352        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
353
354        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
355
356        # The plain x variable shold refer to the innermost x
357        self.assertTrue(self.dap_server.request_setVariable(1, "x", 22)["success"])
358        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
359
360        self.verify_variables(verify_locals, self.dap_server.get_local_variables())
361
362        # In breakpoint 3, there should be no shadowed variables
363        breakpoint3_line = line_number(source, "// breakpoint 3")
364        lines = [breakpoint3_line]
365        breakpoint_ids = self.set_source_breakpoints(source, lines)
366        self.assertEqual(
367            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
368        )
369        self.continue_to_breakpoints(breakpoint_ids)
370
371        locals = self.dap_server.get_local_variables()
372        names = [var["name"] for var in locals]
373        # The first shadowed x shouldn't have a suffix anymore
374        verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
375        self.assertNotIn("x @ main.cpp:17", names)
376        self.assertNotIn("x @ main.cpp:19", names)
377        self.assertNotIn("x @ main.cpp:21", names)
378
379        self.verify_variables(verify_locals, locals)
380
381    @skipIfWindows
382    @skipIfRemote
383    def test_scopes_variables_setVariable_evaluate(self):
384        self.do_test_scopes_variables_setVariable_evaluate(
385            enableAutoVariableSummaries=False
386        )
387
388    @skipIfWindows
389    @skipIfRemote
390    def test_scopes_variables_setVariable_evaluate_with_descriptive_summaries(self):
391        self.do_test_scopes_variables_setVariable_evaluate(
392            enableAutoVariableSummaries=True
393        )
394
395    def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: bool):
396        """
397        Tests the evaluated expression expands successfully after "scopes" packets
398        and permanent expressions persist.
399        """
400        program = self.getBuildArtifact("a.out")
401        self.build_and_launch(
402            program, enableAutoVariableSummaries=enableAutoVariableSummaries
403        )
404        source = "main.cpp"
405        breakpoint1_line = line_number(source, "// breakpoint 1")
406        lines = [breakpoint1_line]
407        # Set breakpoint in the thread function so we can step the threads
408        breakpoint_ids = self.set_source_breakpoints(source, lines)
409        self.assertEqual(
410            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
411        )
412        self.continue_to_breakpoints(breakpoint_ids)
413
414        # Verify locals
415        locals = self.dap_server.get_local_variables()
416        buffer_children = make_buffer_verify_dict(0, 32)
417        verify_locals = {
418            "argc": {
419                "equals": {"type": "int", "value": "1"},
420                "missing": ["indexedVariables"],
421            },
422            "argv": {
423                "equals": {"type": "const char **"},
424                "startswith": {"value": "0x"},
425                "hasVariablesReference": True,
426                "missing": ["indexedVariables"],
427            },
428            "pt": {
429                "equals": {"type": "PointType"},
430                "hasVariablesReference": True,
431                "missing": ["indexedVariables"],
432                "children": {
433                    "x": {
434                        "equals": {"type": "int", "value": "11"},
435                        "missing": ["indexedVariables"],
436                    },
437                    "y": {
438                        "equals": {"type": "int", "value": "22"},
439                        "missing": ["indexedVariables"],
440                    },
441                    "buffer": {
442                        "children": buffer_children,
443                        "equals": {"indexedVariables": 32},
444                    },
445                },
446            },
447            "x": {
448                "equals": {"type": "int"},
449                "missing": ["indexedVariables"],
450            },
451        }
452        self.verify_variables(verify_locals, locals)
453
454        # Evaluate expandable expression twice: once permanent (from repl)
455        # the other temporary (from other UI).
456        expandable_expression = {
457            "name": "pt",
458            "response": {
459                "equals": {"type": "PointType"},
460                "startswith": {
461                    "result": "{x:11, y:22}"
462                    if enableAutoVariableSummaries
463                    else "PointType @ 0x"
464                },
465                "missing": ["indexedVariables"],
466                "hasVariablesReference": True,
467            },
468            "children": {
469                "x": {"equals": {"type": "int", "value": "11"}},
470                "y": {"equals": {"type": "int", "value": "22"}},
471                "buffer": {"children": buffer_children},
472            },
473        }
474
475        # Evaluate from permanent UI.
476        permanent_expr_varref_dict = {}
477        response = self.dap_server.request_evaluate(
478            expandable_expression["name"], frameIndex=0, threadId=None, context="repl"
479        )
480        self.verify_values(
481            expandable_expression["response"],
482            response["body"],
483            permanent_expr_varref_dict,
484            expandable_expression["name"],
485        )
486
487        # Evaluate from temporary UI.
488        temporary_expr_varref_dict = {}
489        response = self.dap_server.request_evaluate(expandable_expression["name"])
490        self.verify_values(
491            expandable_expression["response"],
492            response["body"],
493            temporary_expr_varref_dict,
494            expandable_expression["name"],
495        )
496
497        # Evaluate locals again.
498        locals = self.dap_server.get_local_variables()
499        self.verify_variables(verify_locals, locals)
500
501        # Verify the evaluated expressions before second locals evaluation
502        # can be expanded.
503        var_ref = temporary_expr_varref_dict[expandable_expression["name"]]
504        response = self.dap_server.request_variables(var_ref)
505        self.verify_variables(
506            expandable_expression["children"], response["body"]["variables"]
507        )
508
509        # Continue to breakpoint 3, permanent variable should still exist
510        # after resume.
511        breakpoint3_line = line_number(source, "// breakpoint 3")
512        lines = [breakpoint3_line]
513        breakpoint_ids = self.set_source_breakpoints(source, lines)
514        self.assertEqual(
515            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
516        )
517        self.continue_to_breakpoints(breakpoint_ids)
518
519        var_ref = permanent_expr_varref_dict[expandable_expression["name"]]
520        response = self.dap_server.request_variables(var_ref)
521        self.verify_variables(
522            expandable_expression["children"], response["body"]["variables"]
523        )
524
525        # Test that frame scopes have corresponding presentation hints.
526        frame_id = self.dap_server.get_stackFrame()["id"]
527        scopes = self.dap_server.request_scopes(frame_id)["body"]["scopes"]
528
529        scope_names = [scope["name"] for scope in scopes]
530        self.assertIn("Locals", scope_names)
531        self.assertIn("Registers", scope_names)
532
533        for scope in scopes:
534            if scope["name"] == "Locals":
535                self.assertEquals(scope.get("presentationHint"), "locals")
536            if scope["name"] == "Registers":
537                self.assertEquals(scope.get("presentationHint"), "registers")
538
539    @skipIfWindows
540    @skipIfRemote
541    def test_scopes_and_evaluate_expansion(self):
542        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=False)
543
544    @skipIfWindows
545    @skipIfRemote
546    def test_scopes_and_evaluate_expansion_with_descriptive_summaries(self):
547        self.do_test_scopes_and_evaluate_expansion(enableAutoVariableSummaries=True)
548
549    def do_test_indexedVariables(self, enableSyntheticChildDebugging: bool):
550        """
551        Tests that arrays and lldb.SBValue objects that have synthetic child
552        providers have "indexedVariables" key/value pairs. This helps the IDE
553        not to fetch too many children all at once.
554        """
555        program = self.getBuildArtifact("a.out")
556        self.build_and_launch(
557            program, enableSyntheticChildDebugging=enableSyntheticChildDebugging
558        )
559        source = "main.cpp"
560        breakpoint1_line = line_number(source, "// breakpoint 4")
561        lines = [breakpoint1_line]
562        # Set breakpoint in the thread function so we can step the threads
563        breakpoint_ids = self.set_source_breakpoints(source, lines)
564        self.assertEqual(
565            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
566        )
567        self.continue_to_breakpoints(breakpoint_ids)
568
569        # Verify locals
570        locals = self.dap_server.get_local_variables()
571        # The vector variables might have one additional entry from the fake
572        # "[raw]" child.
573        raw_child_count = 1 if enableSyntheticChildDebugging else 0
574        verify_locals = {
575            "small_array": {"equals": {"indexedVariables": 5}},
576            "large_array": {"equals": {"indexedVariables": 200}},
577            "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
578            "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
579            "pt": {"missing": ["indexedVariables"]},
580        }
581        self.verify_variables(verify_locals, locals)
582
583        # We also verify that we produce a "[raw]" fake child with the real
584        # SBValue for the synthetic type.
585        verify_children = {
586            "[0]": {"equals": {"type": "int", "value": "0"}},
587            "[1]": {"equals": {"type": "int", "value": "0"}},
588            "[2]": {"equals": {"type": "int", "value": "0"}},
589            "[3]": {"equals": {"type": "int", "value": "0"}},
590            "[4]": {"equals": {"type": "int", "value": "0"}},
591        }
592        if enableSyntheticChildDebugging:
593            verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
594
595        children = self.dap_server.request_variables(locals[2]["variablesReference"])[
596            "body"
597        ]["variables"]
598        self.verify_variables(verify_children, children)
599
600    @skipIfWindows
601    @skipIfRemote
602    def test_indexedVariables(self):
603        self.do_test_indexedVariables(enableSyntheticChildDebugging=False)
604
605    @skipIfWindows
606    @skipIfRemote
607    def test_indexedVariables_with_raw_child_for_synthetics(self):
608        self.do_test_indexedVariables(enableSyntheticChildDebugging=True)
609
610    @skipIfWindows
611    @skipIfRemote
612    def test_registers(self):
613        """
614        Test that registers whose byte size is the size of a pointer on
615        the current system get formatted as lldb::eFormatAddressInfo. This
616        will show the pointer value followed by a description of the address
617        itself. To test this we attempt to find the PC value in the general
618        purpose registers, and since we will be stopped in main.cpp, verify
619        that the value for the PC starts with a pointer and is followed by
620        a description that contains main.cpp.
621        """
622        program = self.getBuildArtifact("a.out")
623        self.build_and_launch(program)
624        source = "main.cpp"
625        breakpoint1_line = line_number(source, "// breakpoint 1")
626        lines = [breakpoint1_line]
627        # Set breakpoint in the thread function so we can step the threads
628        breakpoint_ids = self.set_source_breakpoints(source, lines)
629        self.assertEqual(
630            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
631        )
632        self.continue_to_breakpoints(breakpoint_ids)
633
634        pc_name = None
635        arch = self.getArchitecture()
636        if arch == "x86_64":
637            pc_name = "rip"
638        elif arch == "x86":
639            pc_name = "rip"
640        elif arch.startswith("arm"):
641            pc_name = "pc"
642
643        if pc_name is None:
644            return
645        # Verify locals
646        reg_sets = self.dap_server.get_registers()
647        for reg_set in reg_sets:
648            if reg_set["name"] == "General Purpose Registers":
649                varRef = reg_set["variablesReference"]
650                regs = self.dap_server.request_variables(varRef)["body"]["variables"]
651                for reg in regs:
652                    if reg["name"] == pc_name:
653                        value = reg["value"]
654                        self.assertTrue(value.startswith("0x"))
655                        self.assertTrue("a.out`main + " in value)
656                        self.assertTrue("at main.cpp:" in value)
657
658    @no_debug_info_test
659    @skipUnlessDarwin
660    def test_darwin_dwarf_missing_obj(self):
661        """
662        Test that if we build a binary with DWARF in .o files and we remove
663        the .o file for main.cpp, that we get a variable named "<error>"
664        whose value matches the appriopriate error. Errors when getting
665        variables are returned in the LLDB API when the user should be
666        notified of issues that can easily be solved by rebuilding or
667        changing compiler options and are designed to give better feedback
668        to the user.
669        """
670        self.darwin_dwarf_missing_obj(None)
671
672    @no_debug_info_test
673    @skipUnlessDarwin
674    def test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled(self):
675        """
676        Test that if we build a binary with DWARF in .o files and we remove
677        the .o file for main.cpp, that we get a variable named "<error>"
678        whose value matches the appriopriate error. Test with symbol_ondemand_enabled.
679        """
680        initCommands = ["settings set symbols.load-on-demand true"]
681        self.darwin_dwarf_missing_obj(initCommands)
682