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