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