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