1"""Test that hidden ivars in a shared library are visible from the main executable.""" 2 3 4import subprocess 5 6import unittest 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10from lldbsuite.test import lldbutil 11 12 13class HiddenIvarsTestCase(TestBase): 14 def setUp(self): 15 # Call super's setUp(). 16 TestBase.setUp(self) 17 # Find the line number to break inside main(). 18 self.source = "main.m" 19 self.line = line_number(self.source, "// breakpoint1") 20 # The makefile names of the shared libraries as they appear in DYLIB_NAME. 21 # The names should have no loading "lib" or extension as they will be 22 # localized 23 self.shlib_names = ["InternalDefiner"] 24 25 @skipIf( 26 debug_info=no_match("dsym"), 27 bugnumber="This test requires a stripped binary and a dSYM", 28 ) 29 def test_expr_stripped(self): 30 if self.getArchitecture() == "i386": 31 self.skipTest("requires modern objc runtime") 32 else: 33 self.build() 34 self.expr(True) 35 36 def test_expr(self): 37 if self.getArchitecture() == "i386": 38 self.skipTest("requires modern objc runtime") 39 else: 40 self.build() 41 self.expr(False) 42 43 @skipIf( 44 debug_info=no_match("dsym"), 45 bugnumber="This test requires a stripped binary and a dSYM", 46 ) 47 def test_frame_variable_stripped(self): 48 if self.getArchitecture() == "i386": 49 self.skipTest("requires modern objc runtime") 50 else: 51 self.build() 52 self.frame_var(True) 53 54 def test_frame_variable(self): 55 if self.getArchitecture() == "i386": 56 self.skipTest("requires modern objc runtime") 57 else: 58 self.build() 59 self.frame_var(False) 60 61 @unittest.expectedFailure # rdar://18683637 62 def test_frame_variable_across_modules(self): 63 if self.getArchitecture() == "i386": 64 self.skipTest("requires modern objc runtime") 65 else: 66 self.build() 67 self.common_setup(False) 68 self.expect( 69 "frame variable k->bar", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 3"] 70 ) 71 72 def common_setup(self, strip): 73 if strip: 74 exe = self.getBuildArtifact("stripped/a.out") 75 else: 76 exe = self.getBuildArtifact("a.out") 77 # Create a target by the debugger. 78 target = self.dbg.CreateTarget(exe) 79 self.assertTrue(target, VALID_TARGET) 80 81 # Create the breakpoint inside function 'main'. 82 breakpoint = target.BreakpointCreateByLocation(self.source, self.line) 83 self.assertTrue(breakpoint, VALID_BREAKPOINT) 84 85 # Register our shared libraries for remote targets so they get 86 # automatically uploaded 87 environment = self.registerSharedLibrariesWithTarget(target, self.shlib_names) 88 89 # Now launch the process, and do not stop at entry point. 90 process = target.LaunchSimple( 91 None, environment, self.get_process_working_directory() 92 ) 93 self.assertTrue(process, PROCESS_IS_VALID) 94 95 self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) 96 97 # Break inside the foo function which takes a bar_ptr argument. 98 lldbutil.run_break_set_by_file_and_line( 99 self, "main.m", self.line, num_expected_locations=1, loc_exact=True 100 ) 101 102 self.runCmd("run", RUN_SUCCEEDED) 103 104 # The stop reason of the thread should be breakpoint. 105 self.expect( 106 "thread list", 107 STOPPED_DUE_TO_BREAKPOINT, 108 substrs=["stopped", "stop reason = breakpoint"], 109 ) 110 111 # The breakpoint should have a hit count of 1. 112 lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1) 113 114 def expr(self, strip): 115 self.common_setup(strip) 116 117 # This should display correctly. 118 self.expect( 119 "expression (j->_definer->foo)", 120 VARIABLES_DISPLAYED_CORRECTLY, 121 substrs=["= 4"], 122 ) 123 124 self.expect( 125 "expression (j->_definer->bar)", 126 VARIABLES_DISPLAYED_CORRECTLY, 127 substrs=["= 5"], 128 ) 129 130 if strip: 131 self.expect( 132 "expression *(j->_definer)", 133 VARIABLES_DISPLAYED_CORRECTLY, 134 substrs=["foo = 4"], 135 ) 136 else: 137 self.expect( 138 "expression *(j->_definer)", 139 VARIABLES_DISPLAYED_CORRECTLY, 140 substrs=["foo = 4", "bar = 5"], 141 ) 142 143 self.expect( 144 "expression (k->foo)", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 2"] 145 ) 146 147 self.expect( 148 "expression (k->bar)", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 3"] 149 ) 150 151 self.expect( 152 "expression k.filteredDataSource", 153 VARIABLES_DISPLAYED_CORRECTLY, 154 substrs=[" = 0x", '"2 elements"'], 155 ) 156 157 if strip: 158 self.expect( 159 "expression *(k)", 160 VARIABLES_DISPLAYED_CORRECTLY, 161 substrs=["foo = 2", " = 0x", '"2 elements"'], 162 ) 163 else: 164 self.expect( 165 "expression *(k)", 166 VARIABLES_DISPLAYED_CORRECTLY, 167 substrs=[ 168 "foo = 2", 169 "bar = 3", 170 "_filteredDataSource = 0x", 171 '"2 elements"', 172 ], 173 ) 174 175 def frame_var(self, strip): 176 self.common_setup(strip) 177 178 # This should display correctly. 179 self.expect( 180 "frame variable j->_definer->foo", 181 VARIABLES_DISPLAYED_CORRECTLY, 182 substrs=["= 4"], 183 ) 184 185 if not strip: 186 self.expect( 187 "frame variable j->_definer->bar", 188 VARIABLES_DISPLAYED_CORRECTLY, 189 substrs=["= 5"], 190 ) 191 192 if strip: 193 self.expect( 194 "frame variable *j->_definer", 195 VARIABLES_DISPLAYED_CORRECTLY, 196 substrs=["foo = 4"], 197 ) 198 else: 199 self.expect( 200 "frame variable *j->_definer", 201 VARIABLES_DISPLAYED_CORRECTLY, 202 substrs=["foo = 4", "bar = 5"], 203 ) 204 205 self.expect( 206 "frame variable k->foo", VARIABLES_DISPLAYED_CORRECTLY, substrs=["= 2"] 207 ) 208 209 self.expect( 210 "frame variable k->_filteredDataSource", 211 VARIABLES_DISPLAYED_CORRECTLY, 212 substrs=[" = 0x", '"2 elements"'], 213 ) 214 215 if strip: 216 self.expect( 217 "frame variable *k", 218 VARIABLES_DISPLAYED_CORRECTLY, 219 substrs=["foo = 2", "_filteredDataSource = 0x", '"2 elements"'], 220 ) 221 else: 222 self.expect( 223 "frame variable *k", 224 VARIABLES_DISPLAYED_CORRECTLY, 225 substrs=[ 226 "foo = 2", 227 "bar = 3", 228 "_filteredDataSource = 0x", 229 '"2 elements"', 230 ], 231 ) 232