xref: /llvm-project/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py (revision 5b386158aacac4b41126983a5379d36ed413d0ea)
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