/
TestLimitDebugInfo.py
259 lines (226 loc) · 12.4 KB
/
TestLimitDebugInfo.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
"""
Test completing types using information from other shared libraries.
"""
import os
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class LimitDebugInfoTestCase(TestBase):
def _check_type(self, target, name):
exe = target.FindModule(lldb.SBFileSpec("a.out"))
type_ = exe.FindFirstType(name)
self.trace("type_: %s"%type_)
self.assertTrue(type_)
self.assertTrue(type_.IsTypeComplete())
base = type_.GetDirectBaseClassAtIndex(0).GetType()
self.trace("base:%s"%base)
self.assertTrue(base)
self.assertEquals(base.GetNumberOfFields(), 0)
self.assertFalse(base.IsTypeComplete())
def _check_debug_info_is_limited(self, target):
# Without other shared libraries we should only see the member declared
# in the derived class. This serves as a sanity check that we are truly
# building with limited debug info.
self._check_type(target, "InheritsFromOne")
self._check_type(target, "InheritsFromTwo")
def _check_incomplete_frame_variable_output(self):
# Check that the display of the "frame variable" output identifies the
# incomplete types. Currently the expression parser will find the real
# definition for a type when running an expression for any forcefully
# completed types, but "frame variable" won't. I hope to fix this with
# a follow up patch, but if we don't find the actual definition we
# should clearly show this to the user by showing which types were
# incomplete. So this will test verifies the expected output for such
# types. We also need to verify the standard "frame variable" output
# which will inline all of the members on one line, versus the full
# output from "frame variable --raw" and a few other options.
# self.expect("frame variable two_as_member", error=True,
# substrs=["no member named 'one' in 'InheritsFromOne'"])
command_expect_pairs = [
# Test standard "frame variable" output for types to make sure
# "<incomplete type>" shows up where we expect it to
["var two_as_member", [
"(TwoAsMember) ::two_as_member = (two = <incomplete type>, member = 47)"]
],
["var inherits_from_one", [
"(InheritsFromOne) ::inherits_from_one = (One = <incomplete type>, member = 47)"]
],
["var inherits_from_two", [
"(InheritsFromTwo) ::inherits_from_two = (Two = <incomplete type>, member = 47)"]
],
["var one_as_member", [
"(OneAsMember) ::one_as_member = (one = <incomplete type>, member = 47)"]
],
["var two_as_member", [
"(TwoAsMember) ::two_as_member = (two = <incomplete type>, member = 47)"]
],
["var array_of_one", [
"(array::One[3]) ::array_of_one = ([0] = <incomplete type>, [1] = <incomplete type>, [2] = <incomplete type>)"]
],
["var array_of_two", [
"(array::Two[3]) ::array_of_two = ([0] = <incomplete type>, [1] = <incomplete type>, [2] = <incomplete type>)"]
],
["var shadowed_one", [
"(ShadowedOne) ::shadowed_one = (func_shadow::One = <incomplete type>, member = 47)"]
],
# Now test "frame variable --show-types output" which has multi-line
# output and should not always show classes that were forcefully
# completed to the user to let them know they have a type that should
# have been complete but wasn't.
["var --show-types inherits_from_one", [
"(InheritsFromOne) ::inherits_from_one = {",
" (One) One = <incomplete type> {}",
" (int) member = 47",
"}"]
],
["var --show-types inherits_from_two", [
"(InheritsFromTwo) ::inherits_from_two = {",
" (Two) Two = <incomplete type> {}",
" (int) member = 47",
"}"]
],
["var --show-types one_as_member", [
"(OneAsMember) ::one_as_member = {",
" (member::One) one = <incomplete type> {}",
" (int) member = 47",
"}"]
],
["var --show-types two_as_member", [
"(TwoAsMember) ::two_as_member = {",
" (member::Two) two = <incomplete type> {}",
" (int) member = 47",
"}"]
],
["var --show-types array_of_one", [
"(array::One[3]) ::array_of_one = {",
" (array::One) [0] = <incomplete type> {}",
" (array::One) [1] = <incomplete type> {}",
" (array::One) [2] = <incomplete type> {}",
"}"]
],
["var --show-types array_of_two", [
"(array::Two[3]) ::array_of_two = {",
" (array::Two) [0] = <incomplete type> {}",
" (array::Two) [1] = <incomplete type> {}",
" (array::Two) [2] = <incomplete type> {}",
"}"]
],
["var --show-types shadowed_one", [
"(ShadowedOne) ::shadowed_one = {",
" (func_shadow::One) func_shadow::One = <incomplete type> {}",
" (int) member = 47",
"}"]
],
]
for command, expect_items in command_expect_pairs:
self.expect(command, substrs=expect_items)
@skipIf(bugnumber="pr46284", debug_info="gmodules")
@skipIfWindows # Clang emits type info even with -flimit-debug-info
# Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
# by-value functions.
@skipIf(compiler="clang", compiler_version=['<', '7.0'])
def test_one_and_two_debug(self):
self.build()
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self._check_debug_info_is_limited(target)
lldbutil.run_to_name_breakpoint(self, "main",
extra_images=["one", "two"])
# But when other shared libraries are loaded, we should be able to see
# all members.
self.expect_expr("inherits_from_one.member", result_value="47")
self.expect_expr("inherits_from_one.one", result_value="142")
self.expect_expr("inherits_from_two.member", result_value="47")
self.expect_expr("inherits_from_two.one", result_value="142")
self.expect_expr("inherits_from_two.two", result_value="242")
self.expect_expr("one_as_member.member", result_value="47")
self.expect_expr("one_as_member.one.member", result_value="147")
self.expect_expr("two_as_member.member", result_value="47")
self.expect_expr("two_as_member.two.one.member", result_value="147")
self.expect_expr("two_as_member.two.member", result_value="247")
self.expect_expr("array_of_one[2].member", result_value="174")
self.expect_expr("array_of_two[2].one[2].member", result_value="174")
self.expect_expr("array_of_two[2].member", result_value="274")
self.expect_expr("get_one().member", result_value="124")
self.expect_expr("get_two().one().member", result_value="124")
self.expect_expr("get_two().member", result_value="224")
self.expect_expr("shadowed_one.member", result_value="47")
self.expect_expr("shadowed_one.one", result_value="142")
self._check_incomplete_frame_variable_output()
@skipIf(bugnumber="pr46284", debug_info="gmodules")
@skipIfWindows # Clang emits type info even with -flimit-debug-info
# Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
# by-value functions.
@skipIf(compiler="clang", compiler_version=['<', '7.0'])
def test_two_debug(self):
self.build(dictionary=dict(STRIP_ONE="1"))
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self._check_debug_info_is_limited(target)
lldbutil.run_to_name_breakpoint(self, "main",
extra_images=["one", "two"])
# This time, we should only see the members from the second library.
self.expect_expr("inherits_from_one.member", result_value="47")
self.expect("expr inherits_from_one.one", error=True,
substrs=["no member named 'one' in 'InheritsFromOne'"])
self.expect_expr("inherits_from_two.member", result_value="47")
self.expect("expr inherits_from_two.one", error=True,
substrs=["no member named 'one' in 'InheritsFromTwo'"])
self.expect_expr("inherits_from_two.two", result_value="242")
self.expect_expr("one_as_member.member", result_value="47")
self.expect("expr one_as_member.one.member", error=True,
substrs=["no member named 'member' in 'member::One'"])
self.expect_expr("two_as_member.member", result_value="47")
self.expect("expr two_as_member.two.one.member", error=True,
substrs=["no member named 'member' in 'member::One'"])
self.expect_expr("two_as_member.two.member", result_value="247")
self.expect("expr array_of_one[2].member", error=True,
substrs=["no member named 'member' in 'array::One'"])
self.expect("expr array_of_two[2].one[2].member", error=True,
substrs=["no member named 'member' in 'array::One'"])
self.expect_expr("array_of_two[2].member", result_value="274")
self.expect("expr get_one().member", error=True,
substrs=["calling 'get_one' with incomplete return type 'result::One'"])
self.expect("expr get_two().one().member", error=True,
substrs=["calling 'one' with incomplete return type 'result::One'"])
self.expect_expr("get_two().member", result_value="224")
self._check_incomplete_frame_variable_output()
@skipIf(bugnumber="pr46284", debug_info="gmodules")
@skipIfWindows # Clang emits type info even with -flimit-debug-info
# Requires DW_CC_pass_by_* attributes from Clang 7 to correctly call
# by-value functions.
@skipIf(compiler="clang", compiler_version=['<', '7.0'])
def test_one_debug(self):
self.build(dictionary=dict(STRIP_TWO="1"))
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
self._check_debug_info_is_limited(target)
lldbutil.run_to_name_breakpoint(self, "main",
extra_images=["one", "two"])
# In this case we should only see the members from the second library.
# Note that we cannot see inherits_from_two.one because without debug
# info for "Two", we cannot determine that it in fact inherits from
# "One".
self.expect_expr("inherits_from_one.member", result_value="47")
self.expect_expr("inherits_from_one.one", result_value="142")
self.expect_expr("inherits_from_two.member", result_value="47")
self.expect("expr inherits_from_two.one", error=True,
substrs=["no member named 'one' in 'InheritsFromTwo'"])
self.expect("expr inherits_from_two.two", error=True,
substrs=["no member named 'two' in 'InheritsFromTwo'"])
self.expect_expr("one_as_member.member", result_value="47")
self.expect_expr("one_as_member.one.member", result_value="147")
self.expect_expr("two_as_member.member", result_value="47")
self.expect("expr two_as_member.two.one.member", error=True,
substrs=["no member named 'one' in 'member::Two'"])
self.expect("expr two_as_member.two.member", error=True,
substrs=["no member named 'member' in 'member::Two'"])
self.expect_expr("array_of_one[2].member", result_value="174")
self.expect("expr array_of_two[2].one[2].member", error=True,
substrs=["no member named 'one' in 'array::Two'"])
self.expect("expr array_of_two[2].member", error=True,
substrs=["no member named 'member' in 'array::Two'"])
self.expect_expr("get_one().member", result_value="124")
self.expect("expr get_two().one().member", error=True,
substrs=["calling 'get_two' with incomplete return type 'result::Two'"])
self.expect("expr get_two().member", error=True,
substrs=["calling 'get_two' with incomplete return type 'result::Two'"])
self._check_incomplete_frame_variable_output()