xref: /llvm-project/lldb/test/API/functionalities/limit-debug-info/TestLimitDebugInfo.py (revision 80fcecb13c388ff087a27a4b0e7ca3dd8c98eaa4)
1"""
2Test completing types using information from other shared libraries.
3"""
4
5import os
6import lldb
7from lldbsuite.test.decorators import *
8from lldbsuite.test.lldbtest import *
9from lldbsuite.test import lldbutil
10
11
12class LimitDebugInfoTestCase(TestBase):
13    def _check_type(self, target, name):
14        exe = target.FindModule(lldb.SBFileSpec("a.out"))
15        type_ = exe.FindFirstType(name)
16        self.trace("type_: %s" % type_)
17        self.assertTrue(type_)
18        self.assertTrue(type_.IsTypeComplete())
19        base = type_.GetDirectBaseClassAtIndex(0).GetType()
20        self.trace("base:%s" % base)
21        self.assertTrue(base)
22        self.assertEqual(base.GetNumberOfFields(), 0)
23        self.assertFalse(base.IsTypeComplete())
24
25    def _check_debug_info_is_limited(self, target):
26        # Without other shared libraries we should only see the member declared
27        # in the derived class. This serves as a sanity check that we are truly
28        # building with limited debug info.
29        self._check_type(target, "InheritsFromOne")
30        self._check_type(target, "InheritsFromTwo")
31
32        # Check that the statistics show that we had incomplete debug info.
33        stats = self.get_stats()
34        # Find the a.out module info in the stats and verify it has the
35        # "debugInfoHadIncompleteTypes" key value pair set to True
36        exe_module_found = False
37        for module in stats["modules"]:
38            if module["path"].endswith("a.out"):
39                self.assertTrue(module["debugInfoHadIncompleteTypes"])
40                exe_module_found = True
41                break
42        self.assertTrue(exe_module_found)
43        # Verify that "totalModuleCountWithIncompleteTypes" at the top level
44        # is greater than zero which shows we had incomplete debug info in a
45        # module
46        self.assertGreater(stats["totalModuleCountWithIncompleteTypes"], 0)
47
48    def _check_incomplete_frame_variable_output(self):
49        # Check that the display of the "frame variable" output identifies the
50        # incomplete types. Currently the expression parser will find the real
51        # definition for a type when running an expression for any forcefully
52        # completed types, but "frame variable" won't. I hope to fix this with
53        # a follow up patch, but if we don't find the actual definition we
54        # should clearly show this to the user by showing which types were
55        # incomplete. So this will test verifies the expected output for such
56        # types. We also need to verify the standard "frame variable" output
57        # which will inline all of the members on one line, versus the full
58        # output from "frame variable --raw" and a few other options.
59        # self.expect("frame variable two_as_member", error=True,
60        #     substrs=["no member named 'one' in 'InheritsFromOne'"])
61
62        command_expect_pairs = [
63            # Test standard "frame variable" output for types to make sure
64            # "<incomplete type>" shows up where we expect it to
65            [
66                "var two_as_member",
67                [
68                    "(TwoAsMember) ::two_as_member = (two = <incomplete type>, member = 47)"
69                ],
70            ],
71            [
72                "var inherits_from_one",
73                [
74                    "(InheritsFromOne) ::inherits_from_one = (One = <incomplete type>, member = 47)"
75                ],
76            ],
77            [
78                "var inherits_from_two",
79                [
80                    "(InheritsFromTwo) ::inherits_from_two = (Two = <incomplete type>, member = 47)"
81                ],
82            ],
83            [
84                "var one_as_member",
85                [
86                    "(OneAsMember) ::one_as_member = (one = <incomplete type>, member = 47)"
87                ],
88            ],
89            [
90                "var two_as_member",
91                [
92                    "(TwoAsMember) ::two_as_member = (two = <incomplete type>, member = 47)"
93                ],
94            ],
95            [
96                "var array_of_one",
97                [
98                    "(array::One[3]) ::array_of_one = ([0] = <incomplete type>, [1] = <incomplete type>, [2] = <incomplete type>)"
99                ],
100            ],
101            [
102                "var array_of_two",
103                [
104                    "(array::Two[3]) ::array_of_two = ([0] = <incomplete type>, [1] = <incomplete type>, [2] = <incomplete type>)"
105                ],
106            ],
107            [
108                "var shadowed_one",
109                [
110                    "(ShadowedOne) ::shadowed_one = (func_shadow::One = <incomplete type>, member = 47)"
111                ],
112            ],
113            # Now test "frame variable --show-types output" which has multi-line
114            # output and should not always show classes that were forcefully
115            # completed to the user to let them know they have a type that should
116            # have been complete but wasn't.
117            [
118                "var --show-types inherits_from_one",
119                [
120                    "(InheritsFromOne) ::inherits_from_one = {",
121                    "  (One) One = <incomplete type> {}",
122                    "  (int) member = 47",
123                    "}",
124                ],
125            ],
126            [
127                "var --show-types inherits_from_two",
128                [
129                    "(InheritsFromTwo) ::inherits_from_two = {",
130                    "  (Two) Two = <incomplete type> {}",
131                    "  (int) member = 47",
132                    "}",
133                ],
134            ],
135            [
136                "var  --show-types one_as_member",
137                [
138                    "(OneAsMember) ::one_as_member = {",
139                    "  (member::One) one = <incomplete type> {}",
140                    "  (int) member = 47",
141                    "}",
142                ],
143            ],
144            [
145                "var  --show-types two_as_member",
146                [
147                    "(TwoAsMember) ::two_as_member = {",
148                    "  (member::Two) two = <incomplete type> {}",
149                    "  (int) member = 47",
150                    "}",
151                ],
152            ],
153            [
154                "var  --show-types array_of_one",
155                [
156                    "(array::One[3]) ::array_of_one = {",
157                    "  (array::One) [0] = <incomplete type> {}",
158                    "  (array::One) [1] = <incomplete type> {}",
159                    "  (array::One) [2] = <incomplete type> {}",
160                    "}",
161                ],
162            ],
163            [
164                "var  --show-types array_of_two",
165                [
166                    "(array::Two[3]) ::array_of_two = {",
167                    "  (array::Two) [0] = <incomplete type> {}",
168                    "  (array::Two) [1] = <incomplete type> {}",
169                    "  (array::Two) [2] = <incomplete type> {}",
170                    "}",
171                ],
172            ],
173            [
174                "var  --show-types shadowed_one",
175                [
176                    "(ShadowedOne) ::shadowed_one = {",
177                    "  (func_shadow::One) func_shadow::One = <incomplete type> {}",
178                    "  (int) member = 47",
179                    "}",
180                ],
181            ],
182        ]
183        for command, expect_items in command_expect_pairs:
184            self.expect(command, substrs=expect_items)
185
186    @skipIf(bugnumber="pr46284", debug_info="gmodules")
187    @skipIfWindows  # Clang emits type info even with -flimit-debug-info
188    # Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
189    # by-value functions.
190    @skipIf(compiler="clang", compiler_version=["<", "7.0"])
191    def test_one_and_two_debug(self):
192        self.build()
193        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
194
195        self._check_debug_info_is_limited(target)
196
197        lldbutil.run_to_name_breakpoint(self, "main", extra_images=["one", "two"])
198
199        # But when other shared libraries are loaded, we should be able to see
200        # all members.
201        self.expect_expr("inherits_from_one.member", result_value="47")
202        self.expect_expr("inherits_from_one.one", result_value="142")
203        self.expect_expr("inherits_from_two.member", result_value="47")
204        self.expect_expr("inherits_from_two.one", result_value="142")
205        self.expect_expr("inherits_from_two.two", result_value="242")
206
207        self.expect_expr("one_as_member.member", result_value="47")
208        self.expect_expr("one_as_member.one.member", result_value="147")
209        self.expect_expr("two_as_member.member", result_value="47")
210        self.expect_expr("two_as_member.two.one.member", result_value="147")
211        self.expect_expr("two_as_member.two.member", result_value="247")
212
213        self.expect_expr("array_of_one[2].member", result_value="174")
214        self.expect_expr("array_of_two[2].one[2].member", result_value="174")
215        self.expect_expr("array_of_two[2].member", result_value="274")
216
217        self.expect_expr("get_one().member", result_value="124")
218        self.expect_expr("get_two().one().member", result_value="124")
219        self.expect_expr("get_two().member", result_value="224")
220
221        self.expect_expr("shadowed_one.member", result_value="47")
222        self.expect_expr("shadowed_one.one", result_value="142")
223
224        self._check_incomplete_frame_variable_output()
225
226    @skipIf(bugnumber="pr46284", debug_info="gmodules")
227    @skipIfWindows  # Clang emits type info even with -flimit-debug-info
228    # Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
229    # by-value functions.
230    @skipIf(compiler="clang", compiler_version=["<", "7.0"])
231    def test_two_debug(self):
232        self.build(dictionary=dict(STRIP_ONE="1"))
233        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
234
235        self._check_debug_info_is_limited(target)
236
237        lldbutil.run_to_name_breakpoint(self, "main", extra_images=["one", "two"])
238
239        # This time, we should only see the members from the second library.
240        self.expect_expr("inherits_from_one.member", result_value="47")
241        self.expect(
242            "expr inherits_from_one.one",
243            error=True,
244            substrs=["no member named 'one' in 'InheritsFromOne'"],
245        )
246        self.expect_expr("inherits_from_two.member", result_value="47")
247        self.expect(
248            "expr inherits_from_two.one",
249            error=True,
250            substrs=["no member named 'one' in 'InheritsFromTwo'"],
251        )
252        self.expect_expr("inherits_from_two.two", result_value="242")
253
254        self.expect_expr("one_as_member.member", result_value="47")
255        self.expect(
256            "expr one_as_member.one.member",
257            error=True,
258            substrs=["no member named 'member' in 'member::One'"],
259        )
260        self.expect_expr("two_as_member.member", result_value="47")
261        self.expect(
262            "expr two_as_member.two.one.member",
263            error=True,
264            substrs=["no member named 'member' in 'member::One'"],
265        )
266        self.expect_expr("two_as_member.two.member", result_value="247")
267
268        self.expect(
269            "expr array_of_one[2].member",
270            error=True,
271            substrs=["no member named 'member' in 'array::One'"],
272        )
273        self.expect(
274            "expr array_of_two[2].one[2].member",
275            error=True,
276            substrs=["no member named 'member' in 'array::One'"],
277        )
278        self.expect_expr("array_of_two[2].member", result_value="274")
279
280        self.expect(
281            "expr get_one().member",
282            error=True,
283            substrs=["calling 'get_one' with incomplete return type 'result::One'"],
284        )
285        self.expect(
286            "expr get_two().one().member",
287            error=True,
288            substrs=["calling 'one' with incomplete return type 'result::One'"],
289        )
290        self.expect_expr("get_two().member", result_value="224")
291
292        self._check_incomplete_frame_variable_output()
293
294    @skipIf(bugnumber="pr46284", debug_info="gmodules")
295    @skipIfWindows  # Clang emits type info even with -flimit-debug-info
296    # Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
297    # by-value functions.
298    @skipIf(compiler="clang", compiler_version=["<", "7.0"])
299    def test_one_debug(self):
300        self.build(dictionary=dict(STRIP_TWO="1"))
301        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
302
303        self._check_debug_info_is_limited(target)
304
305        lldbutil.run_to_name_breakpoint(self, "main", extra_images=["one", "two"])
306
307        # In this case we should only see the members from the second library.
308        # Note that we cannot see inherits_from_two.one because without debug
309        # info for "Two", we cannot determine that it in fact inherits from
310        # "One".
311        self.expect_expr("inherits_from_one.member", result_value="47")
312        self.expect_expr("inherits_from_one.one", result_value="142")
313        self.expect_expr("inherits_from_two.member", result_value="47")
314        self.expect(
315            "expr inherits_from_two.one",
316            error=True,
317            substrs=["no member named 'one' in 'InheritsFromTwo'"],
318        )
319        self.expect(
320            "expr inherits_from_two.two",
321            error=True,
322            substrs=["no member named 'two' in 'InheritsFromTwo'"],
323        )
324
325        self.expect_expr("one_as_member.member", result_value="47")
326        self.expect_expr("one_as_member.one.member", result_value="147")
327        self.expect_expr("two_as_member.member", result_value="47")
328        self.expect(
329            "expr two_as_member.two.one.member",
330            error=True,
331            substrs=["no member named 'one' in 'member::Two'"],
332        )
333        self.expect(
334            "expr two_as_member.two.member",
335            error=True,
336            substrs=["no member named 'member' in 'member::Two'"],
337        )
338
339        self.expect_expr("array_of_one[2].member", result_value="174")
340        self.expect(
341            "expr array_of_two[2].one[2].member",
342            error=True,
343            substrs=["no member named 'one' in 'array::Two'"],
344        )
345        self.expect(
346            "expr array_of_two[2].member",
347            error=True,
348            substrs=["no member named 'member' in 'array::Two'"],
349        )
350
351        self.expect_expr("get_one().member", result_value="124")
352        self.expect(
353            "expr get_two().one().member",
354            error=True,
355            substrs=["calling 'get_two' with incomplete return type 'result::Two'"],
356        )
357        self.expect(
358            "expr get_two().member",
359            error=True,
360            substrs=["calling 'get_two' with incomplete return type 'result::Two'"],
361        )
362
363        self._check_incomplete_frame_variable_output()
364